gout 使用笔记3

目前使用gout 作为http客户端, 处理数据时看到了respone数据解析。

首先看解析respone header数据:

目前看代码的核心设计逻辑:

1、创建一个Header = headerDecode{} 实例

2、调用实例的(h *headerDecode) Decode(rsp *http.Response, obj interface{}) error 方法

3、如果是传入的obj(BindJSON(&rsp) rsp就是obj)  是http.Header类型也就是type Header map[string][]string类型,

则直接遍历rsp 响应头数据返回即可

case http.Header:
        for k, v := range rsp.Header {
            value[k] = v
        }
        return nil

如果是*http.Header 也就是*map[string][]string 类型,直接将resp heard copy一份即可

case *http.Header:
        *value = rsp.Header.Clone()
        return nil

4、否则安装struct 类型来解析decode(headerSet(rsp.Header), obj, "header")---->

decodeCore(val reflect.Value, sf reflect.StructField, setter setter, tagName string) (err error)
type headerSet map[string][]string

var _ setter = headerSet(nil)

func (h headerSet) Set(value reflect.Value, sf reflect.StructField, tagValue string) error {
    return setForm(h, value, sf, textproto.CanonicalMIMEHeaderKey(tagValue))
}

其中val := reflect.ValueOf(obj) 对传入的obj 获取反射值

复制代码
func decodeCore(val reflect.Value, sf reflect.StructField, setter setter, tagName string) (err error) {
    vKind := val.Kind()

    // elem pointer
    for vKind == reflect.Ptr {
        val = val.Elem()
        vKind = val.Kind()
    }

    // 每个类型都会先尝试set
    // 如果不是结构体才设置。那time.Time类型该如何呢?
    // (time.Time是标准库里面用于表示时间的类型, 用结构体实现)?
    if vKind != reflect.Struct || !sf.Anonymous {
        //todo 是否已经设置过
        err := parseTagAndSet(val, sf, setter, tagName)
        if err != nil {
            return err
        }
    }
//对于一开始val为struct, 获取val,struct type, 然后解析struct 每个filed, 以及对应的val.Field(i)
    if vKind == reflect.Struct {

        typ := val.Type()

        for i := 0; i < typ.NumField(); i++ {

            sf := typ.Field(i)

            if sf.PkgPath != "" && !sf.Anonymous {
                continue
            }

            if err = decodeCore(val.Field(i), sf, setter, tagName); err != nil {
                return
            }
        }
    }

    return nil
}
复制代码

处理struct 每个Field 的tagname value

复制代码
func parseTagAndSet(val reflect.Value, sf reflect.StructField, setter setter, tagName string) error {
    tagName = sf.Tag.Get(tagName)
    tagName, _ = parseTag(tagName)

    if tagName == "" {
        tagName = sf.Name---->复制tagname
    }

    if tagName == "" {
        return nil
    }

    return setter.Set(val, sf, tagName) //---> setter 指向的也就是headerSet(rsp.Header)--->rsp.Header

}
复制代码

根据 一开始创建来的 rsp.header , struct.Field(i)的tagname 以及reflect value

根据rsp.header 读取 tagname 对应的val, 然后设置reflect value 为 val

复制代码
func setForm(m map[string][]string,
    value reflect.Value,
    sf reflect.StructField,
    tagValue string,
) error {

    vs, ok := m[tagValue]
    if !ok {
        //fmt.Printf("tagName = %s:%v\n", tagValue, m)
        return nil
    }

    switch value.Kind() {
    case reflect.Slice:
        return setSlice(vs, sf, value)
    case reflect.Array:
        if len(vs) != value.Len() {
            return fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
        }

        return setArray(vs, sf, value)
    }

    var val string
    if len(vs) > 0 {
        val = vs[0]
    }

    return setBase(val, sf, value)
}
复制代码
复制代码
package main

import "fmt"

func main() {
    var i interface{} = 42

    // Type assertion to extract the underlying concrete value as an int.
    if val, ok := i.(int); ok {
        fmt.Printf("i is an int: %d\n", val)
    } else {
        fmt.Println("i is not an int")
    }
  switch val := i.(type) {
    case int:
        fmt.Printf("i is an int: %d\n", val)
    case string:
        fmt.Printf("i is a string: %s\n", val)
    default:
        fmt.Println("i is of an unknown type")
    }  
}
复制代码

 

posted @   codestacklinuxer  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
历史上的今天:
2021-08-01 redis:字典-hash
点击右上角即可分享
微信分享提示