结构体标签
结构体标签
结构体的字段除了名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记。比如在我们解析json或生成json文件时,常用到encoding/json包,它提供一些默认标签,例如:omitempty标签可以在序列化的时候忽略0值或者空值;而“-”标签的作用是不进行序列化,其效果和直接将结构体中的字段写成小写的效果一样。
type Info struct {
Name string
Age int `json:"age,omitempty"`
Sex string
}
在序列化和反序列化的时候,也支持类型转化等操作。如
type Info struct {
Name string
Age int `json:"age,string"`
//这样生成的json对象中,age就为字符串
Sex string
}
定义结构体时,可以通过这些默认标签来设定结构体成员变量,使之在序列化后得到特殊的输出。
示例代码:
type Student struct {
Name string `json:"-"` //“-”作用是不进行序列化,效果和将结构体字段写成小写一样。
Age int `json:"Age,omitempty"` // “omitempty”作用是在序列化的时候忽略0值或空值。
Id int `json:"idx,string"` // 序列化时,类型转化为string
Sex string `json:"sex"`
}
func main() {
stu := Student{Name:"Andy", Age:0, Id:100}
ret, err:= json.Marshal(stu)
if err != nil {
panic(err)
}
fmt.Println("json info1 ret=", string(ret))
}
序列化应用tag
通过前面序列化章节编写的测试代码,我们可以看到。生成的序列化json字符串是将struct 结构体的字段名作为json字符串的key,将字段值作为value的。
这在实际应用过程中容易出现问题。为了方便导出包作用域,我们在定义结构体时,要将字段名的首字母大写,而实际应用中,当我们用json和外部API进行交互的时候, 其他语言并不像Go这样用大写和小写来控制变量的作用域。所以借助结构体标签,可以得到小写字母开头的字串。
很自然的,可以想到,将struct 结构体中的字段名改为小写字母不就可以解决这个冲突吗?但实际测试发现,如果转为小写,则丢失了包作用域,Marshal() 函数不能正常完成序列化,得到的往往是空值。后续再来测试。
这里,就需要用到我们上节提到的结构体标签tag来解决这一问题了。从新定义结构体类型。
注意语法: stu_name 一定要使用“ “ 包裹起来。
type Student struct {
Name string `json: "stu_name"`
Id int `json: "stu_id"`
Age int // 剩余两个字段不添加tag,用以比较
Addr string
}
序列化方法与之前的序列化方法一致。使用json.Marshal() 可以直接得到json字符串,输出结果为:
stu序列化后 = {“stu_name”:”瞎么海”,”stu_id”:110,”Age”:33,”Addr”:”天津市海河”}
可以看到,此时json字符串的key值为“stu_name”和“stu_id”,是我们定义结构体时指定的tag。而没有指定tag的Age和Addr,key值依然是原来字段的名字。
如果改为小写会怎样呢?测试:
type Student struct {
Name string `json: "stu_name"`
Id int `json: "stu_id"`
age int // 将两个不添加tag的字段名改为小写
addr string
}
当然,结构体变量赋值时也要指定小写的字段名进行赋值。
输出结果为:
stu序列化后 = {“stu_name”:”瞎么海”,”stu_id”:110}
可以看到,程序没有报错。但指定为小写字段名的两个字段age、addr没有成功转换为json字串。