Golang实践录:反射reflect的一些研究及代码汇总

Posted 李迟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang实践录:反射reflect的一些研究及代码汇总相关的知识,希望对你有一定的参考价值。

本文汇总一些工程中使用到的和 reflect 有关的代码示例。由于是代码片段,不一定保证完整。

解析json

本节介绍解析json的一些方法。json 可来自文件,也可来自字符串,无论哪种,都是先转换成[]byte,再调用json.Unmarshal解析。
有时候并不关注完整的 json 格式,我们可以只取其中一部分字段,因此,可使用map[string]interface{}来接收解析结果(注意如是数组,则须使用数组形式)。

从json文件解析其字段

    file, err := os.Open(filename)
    if err != nil {
        fmt.Printf("open file %s error: %s\\n", filename, err)
        return
    }
    defer file.Close()

    read := io.Reader(file)

    data, _ := ioutil.ReadAll(read)
    var v []map[string]interface{}
    err = json.Unmarshal(data, &v)
    if err != nil {
        fmt.Printf("Unmarshal error: %s\\n", err)
        return
    }
    
    // 假定filename里面有很多的json数组,一一遍历
    for _, idx := range v {
        fmt.Println(idx["foo"])
        ...
    }
    

从json字符串解析

一个简单的示例,从字符串组装,到解析,到提取其中某个字段。

func TestJsonSimple(t *testing.T) {
// 原始json字符串不能格式化,必须转换成[]byte
orgJsonString :=
`{"enID":"ID250","exID":"ID251","type":1,"money":250.44,"distance":274050}`

    // 虽然不知道具体结构体,但知道json只有一个,不是数组
    var data map[string]interface{}
	// 解析
    err := json.Unmarshal([]byte(orgJsonString), &data)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Printf("%#v\\n", data);
    fmt.Println(data["money"]) // 并不关心其它字段,只抽取所需的
    fmt.Println(data["money1"]) // 不存在,返回nil
}

输出:

map[string]interface {}{"distance":274050, "enID":"ID250", "exID":"ID251", "money":250.44, "type":1}
250.44
<nil>

json中嵌套数组,并获取数组内容:

func showInterface(origin interface{}) {
    switch reflect.TypeOf(origin).Kind() {
    case reflect.Slice, reflect.Array:
        s := reflect.ValueOf(origin)
        for i := 0; i < s.Len(); i++ {
            fmt.Printf("%d: %v\\n", i, s.Index(i))
        }
    case reflect.String:
        s := reflect.ValueOf(origin)
        fmt.Printf("only string %v\\n", s.String())
    case reflect.Int:
        s := reflect.ValueOf(origin)
        fmt.Printf("only int %v\\n", s.Int())
    }
}

func TestJsonArray(t *testing.T) {
    orgJsonString :=
`{"enID":"ID500","exID":"ID501","type":2,"money":27.00,"distance":28322,"splitInfo":[{"index":1,"pTag":"11","pMoney":700},{"index":2,"pTag":"12","pMoney":2000}]}`

    // 解析
    var data map[string]interface{}
	err := json.Unmarshal([]byte(orgJsonString), &data)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Printf("org json:\\n%#v\\n\\n", data);
    showInterface(data["enID"])
    showInterface(data["splitInfo"])
}

data["splitInfo"]是一个interface,此刻并不知道具体的内容,因此无法再获取内部的字段或长度。可以利用reflect.TypeOf获取类型,如是数组,需要遍历。详见代码。
输出:

org json:
map[string]interface {}{"distance":28322, "enID":"ID500", "exID":"ID501", "money":27, "splitInfo":[]interface {}{map[string]interface {}{"index":1, "pMoney":700, "pTag":"11"}, map[string]interface {}{"index":2, "pMoney":2000, "pTag":"12"}}, "type":2}

only string ID500
0: map[index:1 pMoney:700 pTag:11]
1: map[index:2 pMoney:2000 pTag:12]

接上,如果只需要获取data["splitInfo"]的长度。注意,此处是知道该字段是数组,但不知道其内容(或不关注内容),可直接用reflect.ValueOf求出长度,如下:

    mylen := reflect.ValueOf(data["splitInfo"]).Len()
    fmt.Println("splitInfo len: ", mylen)

以上是关于Golang实践录:反射reflect的一些研究及代码汇总的主要内容,如果未能解决你的问题,请参考以下文章

Golang实践录:静态资源文件整合:web服务

golang基础--reflect反射

Golang实践录:静态资源文件整合:初步使用

Golang实践录:调用C++函数

Java中反射机制(Reflection)研究及源码演示

Golang实践录:调用C++函数的优化