go結構體總結(+Json 高級進階) + 接口

1.結構體和Json, 成員變量名必須要大寫字母開頭,否則解析失敗

go中根據首字母的大小寫來確定可以訪問的權限。無論是方法名、常量、變量名還是結構體的名稱,如果首字母大寫,則可以被其他的包訪問;如果首字母小寫,則只能在本包中使用

type CurrUser struct{
    Name      string  `json:"name,omitempty"`  //如果爲空值,則轉json的時候,該字段不生成,從沒有該字段的json字符串轉結構體的時候,不報錯,爲默認值
    No        int     `json:"no,omitempty"`
    Uniqueid  string  `json:"uniqueid,omitempty"`
}

結構體中的成員變量是byte切片的時候,生成的json會自動進行base64編碼,解析的時候,反過來也同理

type MrEventDataMessage struct {	
	Body   []byte       `json:"body,omitempty"`
}
mrEventMessage := MrEventDataMessage{Body:[]byte("xiaoyu你好!")}
str, _ := json.Marshal(&mrEventMessage)
log.Error("BagItemSub MrEventMessage  %s", string(str))
decodeBytes, _ := base64.StdEncoding.DecodeString("eGlhb3l15L2g5aW977yB")
fmt.Println(string(decodeBytes))

結構體只要包含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()		
		

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章