1.结构体和Json

成员变量名必须要大写字母开头,否则解析失败

json字符串转对象的时候,可以不区分大小写,如以下 {"uniqueid":"123", "no":"500"}都可以成功Unmarshal

go中根据首字母的大小写来确定可以访问的权限。无论是方法名、常量、变量名还是结构体的名称,如果首字母大写,则可以被其他的包访问;如果首字母小写,则只能在本包中使用

type CurrUser struct{
     Name      string  `json:"name,omitempty"`  //如果为空值,则转json的时候,该字段不生成,从没有该字段的json字符串转结构体的时候,不报错,为默认值
     No        int     `json:"no,omitempty"`
     Uniqueid  string  `json:"uniqueid,omitempty"`
 }

结构体中的成员变量是byte切片的时候,生成的json会自动进行base64编码,解析的时候,反过来也同理

Message := DataMessage{Body:[]byte("xiaoyu你好!")}
	str, _ := json.Marshal(&Message)
	// fmt.Printf("BagItemSub Message  %s", string(str))
	// decodeBytes, _ := base64.StdEncoding.DecodeString("eGlhb3l15L2g5aW977yB")	
	// fmt.Println(string(decodeBytes))
	//strJson := "{\"body\" : \"你好!\"}"
	strJson := string(str)
	msg := DataMessage{}
	json.Unmarshal([]byte(strJson), &msg)

结构体只要包含json字符串中部分需要解析的成员就可以了,不需要使用的字段可以不写在结构体的成员变量中

结构体中嵌套的结构体,可以是指针

type InStr struct {
     Age int64 `json:"age,omitempty"`
 }type TestStruct struct {
     Name  string `json:"name,omitempty"`
     ID    int32  `json:"id,omitempty"`
     MyAge *InStr `json:"myage,omitempty"`
     No    *int64 `json:"no,omitempty"`
 }inStr := InStr{Age: 20}
     iNo := int64(110)
     testStruct := TestStruct{Name: "xiaoyu",
         ID:    16,
         MyAge: &inStr,
         No:    &iNo}
     fmt.Println(testStruct)
     byteJson, _ := json.Marshal(testStruct)
     fmt.Println(string(byteJson))生成嵌套json:
 {"name":"xiaoyu","id":16,"myage":{"age":20},"no":110}

结构体成员如果是枚举类型,最终生成的json值也是 数值类型,比如赋值TeamType_DISCUZ,实际值为1

type TeamType int32
const (
     TeamType_GROUP    TeamType = 0
     TeamType_DISCUZ   TeamType = 1
     TeamType_CHATROOM TeamType = 2
 )type Team struct {
     Id       string            `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
     Name     string            `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
     HeadImg  string            `protobuf:"bytes,3,opt,name=head_img,json=headImg" json:"head_img,omitempty"`
     Type     TeamType          `protobuf:"varint,4,opt,name=type,enum=com.sencent.im.model.TeamType" json:"type,omitempty"`
     Silenced bool              `protobuf:"varint,5,opt,name=silenced" json:"silenced,omitempty"`
     
 }
 team := &Team{Id : "123", Type : TeamType_DISCUZ}
 byteJson, _ := json.Marshal(team)
 strJson := string(byteJson)  "{"id":"123","type":1}"

结构体中嵌套不确定结构的结构体,使用接口就行了:

type Group struct {    

Name     string            `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
     HeadImg  string            `protobuf:"bytes,3,opt,name=head_img,json=headImg" json:"head_img,omitempty"`    
 }
 type Msg struct {    
     Info     string            `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"`
 }type ApiRsp struct{
     ErrCode int64  `protobuf:"bytes,1,opt,name=err_code" json:"err_code,omitempty"`
     Data  interface{}    `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"`  
     Msg  interface{}    `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"` 
 }func main(){
     group := Group{Name:"xiaoyu"}
     msg := Msg{Info : "i don't konw"}
     apiRsp := &ApiRsp{ErrCode : 1, Data : &group, Msg :&msg}
     byteJson, _ := json.Marshal(apiRsp)
     strJson := string(byteJson)  
     fmt.Println(strJson)
 }

2.利用反射获得结构体的成员变量名

package main
import (
     "fmt"
     "reflect"
 )type User struct{
     UName string
 }type resume struct {
     Name string //`json:"name" doc:"我的名字"`
     Sex  string //`json:"name" doc:"我的名字"`
     Age  int
     Tel  string
     SUser User
 }//注意stru是接口,传递参数的时候是结构体指针
 func findDoc(stru interface{}) map[string]string {
     t := reflect.TypeOf(stru).Elem()
     doc := make(map[string]string)    for i := 0; i < t.NumField(); i++ {
         //doc[t.Field(i).Tag.Get("json")] = t.Field(i).Tag.Get("doc")
         fmt.Println(t.Field(i).Name)
     }    return doc
}
func main() {
     stru := resume{}
     doc := findDoc(&stru)
     fmt.Printf("name字段为:%s\n", doc["name"])
 }


2.接口

iValue := 100 //默认是int类型,要赋值给int32 /int64要进行类型转换
package main
 import "fmt" 
 func main() {
     var a interface{} //没有赋值(类型,实现任何接口)是nil类型
 //a.(string) 会崩溃,空接口转其他类型会崩溃,使用ok进行判断
     //var b string
     //a = "asdasdasdasd"
     //a = 32 int类型, 不同于int32/int64,不能直接转换
     a = int32(32) //int64类型
     switch a.(type){
     case string:
         fmt.Print("string\n")
     case int:
         fmt.Print("int\n")
     case int32:
         fmt.Print("int32\n")
     case int64:
         fmt.Print("int64\n")
     case nil:
         fmt.Print("nil\n")        
     }
     if c, ok := a.(int32); ok{
         fmt.Println(c)
     }
     value := a.(int64)  //类型不对,会crash
     fmt.Println(value)
 }

运用案例:

解析的时候,要将Data 转为具体的对象数组(切片),不然解析不到对象,注意要使用&arrAccount指针

type ApiRsp struct{
     ErrCode int64              `protobuf:"bytes,1,opt,name=error_code" json:"error_code"`
     //如果Data为nil,则生成的json中Data的值为null,不雅观,所以赋值一个大小为0的切片 
     Data    interface{}       `protobuf:"bytes,1,opt,name=data" json:"data"`  //, omitempty
     Msg     string            `protobuf:"bytes,1,opt,name=message" json:"message"` 
 }func (apiRsp *ApiRsp)GetJsonString() string{
     strJson, _ := json.Marshal(apiRsp)
     return string(strJson)    
 }//data必须是数组,切片,对象指针或者nil,能够自动将obj转为[]
 //{"err_code":0,"data":[数组],"msg":""}
 func ApiHttpRsp(c *gin.Context, errCode int64, data interface{}, msg string ){
     empData := make([]interface{}, 0) //避免Data :[NULL]    
     apiRsp := &ApiRsp{ErrCode : 0, Data : empData, Msg : ""}
     apiRsp.ErrCode = errCode
     apiRsp.Msg = msg
     if (nil != data){
         strType := reflect.TypeOf(data).Kind() //如果data是nil,.Kind()方法会报错
         if (reflect.Ptr == strType){
             empData = append(empData, data)
             apiRsp.Data = empData
         }else{
             apiRsp.Data = data
         }        
     }        
     strRsp := apiRsp.GetJsonString()    
     c.String(http.StatusOK, strRsp)    
 }//比如这样的json
 {
     "error_code": 0,
     "data": [{
         "id": "123456",
         "token": "77888",
         "token_gen_time": 1577413605,        
     }],
     "message": ""
 }

那要怎么解析呢成对象呢?比如有Account对象

type Account struct {
     Id            string   `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`    
     Token         string   `protobuf:"bytes,3,opt,name=token" json:"token,omitempty"`
     TokenGenTime  int64    `protobuf:"varint,4,opt,name=token_gen_time,json=tokenGenTime" json:"token_gen_time,omitempty"`    
 }        apiRsp := &ApiRsp{}
         arrAccount  := make([]*model.Account, 0)
         apiRsp.Data = &arrAccount  //解析的时候,要将Data 转为具体的对象数组(切片),不然解析不到对象,注意要使用&arrAccount指针。否则apiRsp.Data这个接口是切片类型,这样的转换失败apiRsp.Data.(*[]*model.Account)
     
         log.Debug("%s rsp: %s", strPath, strRsp)        
         if err := json.Unmarshal([]byte(strRsp), &apiRsp); err != nil {
             log.Error("loginRes Unmarshal error", err)
             return
         }    
         //g_account = arrAccount[0] //这是一种方法
         arrData, ok := apiRsp.Data.(*[]*model.Account) 
 if ok{
     g_account = (*arrData)[0]   //这也是一种方法}
         //strType := reflect.TypeOf(apiRsp.Data).String()

解析[{},{}]这样的数组json

var thresholdList []*Threshold	
	var err error = nil
	err := json.Unmarshal([]byte(thresholds), &thresholdList)