本文汇总一些工程中使用到的和 reflect 有关的代码示例。由于是代码片段,不一定保证完整。但其思想可以参考。
解析json
本节介绍解析json的一些方法。json 可来自文件,也可来自字符串,无论哪种,都是先转换成[]byte
,再调用json.Unmarshal
解析。 有时候并不关注完整的 json 格式,因为完整的 json 数据可能非常多,而我们只需其中一个字段或部分字段,因此,可使用map[string]interface{}
来接收解析结果(注意如果 json 本身是数组,则 map 必须使用数组形式)。
从json文件解析其字段
首先打开文件,再读取其内容,再调用json.Unmarshal
即可。
file,err:=os.Open(filename)iferr!=nil{fmt.Printf("openfile%serror:%s\n",filename,err)return}deferfile.Close()read:=io.Reader(file)data,_:=ioutil.ReadAll(read)varv[]map[string]interface{}err=json.Unmarshal(data,&v)iferr!=nil{fmt.Printf("Unmarshalerror:%s\n",err)return}//假定filename里面有很多的json数组,一一遍历for_,idx:=rangev{fmt.Println(idx["foo"])...}
从json字符串解析
一个简单的示例,从字符串组装,到解析,到提取其中某个字段。
funcTestJsonSimple(t*testing.T){//原始json字符串不能格式化,必须转换成[]byteorgJsonString:=`{"enID":"ID250","exID":"ID251","type":1,"money":250.44,"distance":274050}`//虽然不知道具体结构体,但知道json只有一个,不是数组vardatamap[string]interface{}//解析err:=json.Unmarshal([]byte(orgJsonString),&data)iferr!=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 中有嵌套的数组,获取数组内容代码如下:
funcshowInterface(origininterface{}){switchreflect.TypeOf(origin).Kind(){casereflect.Slice,reflect.Array:s:=reflect.ValueOf(origin)fori:=0;i<s.Len();i++{fmt.Printf("%d:%v\n",i,s.Index(i))}casereflect.String:s:=reflect.ValueOf(origin)fmt.Printf("onlystring%v\n",s.String())casereflect.Int:s:=reflect.ValueOf(origin)fmt.Printf("onlyint%v\n",s.Int())}}funcTestJsonArray(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}]}`//解析vardatamap[string]interface{}err:=json.Unmarshal([]byte(orgJsonString),&data)iferr!=nil{fmt.Println(err.Error())return}fmt.Printf("orgjson:\n%#v\n\n",data);showInterface(data["enID"])showInterface(data["splitInfo"])}
data["splitInfo"]
是一个interface
,此刻并不知道具体的内容,因此无法再获取内部的字段或长度。可以利用reflect.TypeOf
获取类型,如是数组,需要遍历。详见代码。 输出内容如下:
orgjson: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}onlystringID5000:map[index:1pMoney:700pTag:11]1:map[index:2pMoney:2000pTag:12]
接上,如果只需要获取data["splitInfo"]
的长度。注意,此处已经知道了该字段是数组,只是不知道其内容罢了(或不关注内容),那么可以直接用reflect.ValueOf
求出长度,如下:
mylen:=reflect.ValueOf(data["splitInfo"]).Len()fmt.Println("splitInfolen:",mylen)
更多示例,待后续研究。