fla可以做网站么,南宁h5建站,帝国cms与wordpress,app开发公司有哪些部门1. 定义
Go语言支持一种特殊的字段只需要提供类型而不需要写字段名的字段#xff0c;称之为匿名字段或者嵌套字段。
所谓匿名字段实际上是一种结构体嵌套的方式#xff0c;所以也可以称作嵌套字段。
这种方式可以实现组合复用#xff0c;即通过匿名字段#xff0c;结构体…1. 定义
Go语言支持一种特殊的字段只需要提供类型而不需要写字段名的字段称之为匿名字段或者嵌套字段。
所谓匿名字段实际上是一种结构体嵌套的方式所以也可以称作嵌套字段。
这种方式可以实现组合复用即通过匿名字段结构体可以直接访问嵌套结构体的字段和方法而无需通过字段名或类型进行嵌套。这些方法和属性被称为“提升”的方法和属性。通过类型名称也可以直接访问匿名嵌入字段。
2.代码示例
2.1 简单示例
package mainimport (fmt
)type Person struct {Name stringAge intPhone string
}func (p *Person) playBasketball() {fmt.Println(打篮球...)
}type Employee struct {PersonEmployeeId int
}// 测试匿名字段
func TestAnonymous() {emp : Employee{Person: Person{Name: Liu,Age: 20,Phone: 18899999999,},EmployeeId: 101,}// 可直接使用emp调用嵌套类型的方法emp.playBasketball()fmt.Println(id: , emp.EmployeeId)// 可直接使用emp打印出嵌套类型的所有字段fmt.Println(name: emp.Name)fmt.Println(age: , emp.Age)fmt.Println(name: emp.Phone)// 通过匿名类型名来访问fmt.Println(类型访问的id: , emp.Person.Name)
}func main() {TestAnonymous()
}
2.2 嵌套类型有重复字段
在上面的例子中Employee 结构体嵌套了 Person 结构体通过这种方式Employee 可以直接访问 Person 的字段和方法而无需使用类似 emp.Person.Name这样的方式。
需要注意的是如果结构体中有多个 匿名字段并且它们拥有相同的字段名那么在访问这个同名字段时需要指定嵌套结构体的类型以避免歧义。例如
package mainimport (fmt
)type Person struct {Name stringAge intPhone string
}func (p *Person) contact() {fmt.Println(Person联系...)
}// 合同
type Contract struct {EmployeeId intPhone string
}func (p *Contract) contact() {fmt.Println(Contract联系...)
}type Employee struct {PersonEmployeeId intContract
}// 测试匿名字段
func TestAnonymous() {emp : Employee{Person: Person{Name: Liu,Age: 20,Phone: 18899999999,},EmployeeId: 101,Contract: Contract{EmployeeId: 101,Phone: 16699999999,},}// 多个匿名类型字段的字段名称可以相同这样在访问时需要通过匿名类型名来访问//emp.contact() //会报错emp.Person.contact()emp.Contract.contact()fmt.Println(id: , emp.EmployeeId)// 可直接使用emp打印出嵌套类型的所有字段fmt.Println(name: emp.Name)fmt.Println(age: , emp.Age)//fmt.Println(name: emp.Phone)//这里会报错因为Person和Contract中都有Phone字段fmt.Println(person phone: , emp.Person.Phone)fmt.Println(contract phone: , emp.Contract.Phone)
}func main() {TestAnonymous()
}在这个例子中Person 和 Contract 都有 Phone 字段因此在访问时需要指定具体的类型以避免歧义。 同样的Person 和 Contact 都有 contact 方法因此在访问时也需要指定具体的类型以避免歧义。 如果不指定则会编译报错.
3. 结构体匿名字段的Json序列化、反序列化
结构体序列化规则
注意可导出的字段(首字母大写)才能参与Json的序列化
标签json的key有标签,json:xxkeyxx无标签key结构体原属性字段有标签,json:-会被忽略不参与序列化有标签,json:xxx,omitempty代表该字段为空值时,会被忽略。其中xxx可以省略,不可以省略。 如json:,omitempty有标签,json:xxx,string代表输出类型会转化为字符串。其中xxx也可以省略 它只适用于字符串、浮点数、整数类型的字段
3.1 代码示例
package mainimport (encoding/jsonfmt
)type Student struct {// 指定json标签时,序列化的key为标签值:nameName string json:name// 不指定序列化标签时key为原属性:AgeAge int// 当标签值为json:-,代表改字段会被忽略Home string json:-// 标签指定omitempty选项,代表该字段为空值时,会被忽略Phone string json:phone,omitempty// 标签指定string选项,代表输出类型会转化为字符串// 它只适用于字符串、浮点数、整数类型的字段Score float64 json:score,string
}func TestMarshal() {// 声明初始化结构体student1 : Student{Name: Liu,Age: 18,Home: 北京,Score: 90.5,Phone: ,}// 序列化json1, _ : json.Marshal(student1)fmt.Printf(序列化json:%s\n, json1)
}
func main() {TestMarshal()
}输出结果
序列化json:{name:Liu,Age:18,score:90.5}
3.2 匿名字段序列化
3.2.1 无JSON标签
a. 字段标签不重复
School.Name和Student.NameJson标签不一致。
package mainimport (encoding/jsonfmt
)// 学校
type School struct {Name string json:schoolNameAddress string json:schoolAddress
}// 学生
type Student struct {Name string json:name// 匿名字段,而且没有json标签School
}// 序列化-匿名字段 (默认字段不冲突)
func TestAnonymousTagDifferent() {var student Student{Name: XiaoMing,School: School{Name: 北京大学,Address: 北京海淀区,},}jsonByte, _ : json.Marshal(student)fmt.Printf(json: %s \n, jsonByte)
}
func main() {TestAnonymousTagDifferent()
}结果
json: {name:XiaoMing,schoolName:北京大学,schoolAddress:北京海淀区} b. 字段标签重复
School.Name和Student.NameJson标签一致都是 json:name。
package mainimport (encoding/jsonfmt
)// 学校
type School struct {Name string json:nameAddress string json:schoolAddress
}// 学生
type Student struct {Name string json:name// 匿名字段,而且没有json标签School
}// 序列化-匿名字段 (默认字段冲突)
func TestAnonymousTagDifferent() {var student Student{Name: XiaoMing,School: School{Name: 北京大学,Address: 北京海淀区,},}jsonByte, _ : json.Marshal(student)fmt.Printf(json: %s \n, jsonByte)
}
func main() {TestAnonymousTagDifferent()
}结果
json: {name:XiaoMing,schoolAddress:北京海淀区} 根据上面代码得知如果字段标签冲突冲突的匿名字段会被忽略。
3.2.2 有JSON标签
当匿名字段设置json标签时, 就不会出现冲突的情况因为序列化后的匿名字段会变成对象。
package mainimport (encoding/jsonfmt
)// 学校
type School struct {Name string json:nameAddress string json:schoolAddress
}// 学生
type Student struct {Name string json:name// 匿名字段,而且没有json标签School json:school
}// 序列化-匿名字段 (默认字段冲突)
func TestAnonymousTagDifferent() {var student Student{Name: XiaoMing,School: School{Name: 北京大学,Address: 北京海淀区,},}jsonByte, _ : json.Marshal(student)fmt.Printf(json: %s \n, jsonByte)
}
func main() {TestAnonymousTagDifferent()
}结果
json: {name:XiaoMing,school:{name:北京大学,schoolAddress:北京海淀区}}
对比前面两个代码可以发现 当匿名字段设置json标签时序列化后的匿名字段会变成对象
3.3 匿名字段反序列化
3.3.1 无JSON标签
a. 字段标签不重复
package mainimport (encoding/jsonfmt
)// 学校
type School struct {Name string json:schoolNameAddress string json:schoolAddress
}// 学生
type Student struct {Name string json:name// 匿名字段,而且没有json标签School
}// 反序列化-匿名字段 (默认字段不冲突)
func TestUnMarshal() {jsonStr : {name:XiaoMing,schoolName:北京大学,schoolAddress:北京海淀区}stu : Student{}err : json.Unmarshal([]byte(jsonStr), stu)if err ! nil {fmt.Println(err)return}fmt.Printf(反序列化结果%v, stu)fmt.Println()
}
func main() {TestUnMarshal()
}结果
反序列化结果{Name:XiaoMing School:{Name:北京大学 Address:北京海淀区}}b. 字段标签重复
package mainimport (encoding/jsonfmt
)// 学校
type School struct {Name string json:nameAddress string json:schoolAddress
}// 学生
type Student struct {Name string json:name// 匿名字段,而且没有json标签School
}// 反序列化-匿名字段 (默认字段冲突)
func TestUnMarshal() {jsonStr : {name:XiaoMing,schoolAddress:北京海淀区}stu : Student{}err : json.Unmarshal([]byte(jsonStr), stu)if err ! nil {fmt.Println(err)return}fmt.Printf(反序列化结果%v, stu)fmt.Println()
}
func main() {TestUnMarshal()
}结果
反序列化结果{Name:XiaoMing School:{Name: Address:北京海淀区}}其中如果上面示例中将jsonStr改为如下
jsonStr : {name:XiaoMing,name:北京大学,schoolAddress:北京海淀区}
那么结果如下可以看到Name的值变了但是School中的依然没有值
反序列化结果{Name:北京大学 School:{Name: Address:北京海淀区}}从上面示例中可以看到 当字段标签重复时,反序列化会优先给主属性字段赋值。
3.3.2 有JSON标签
示例代码
package mainimport (encoding/jsonfmt
)// 学校
type School struct {Name string json:nameAddress string json:schoolAddress
}// 学生
type Student struct {Name string json:name// 匿名字段,而且没有json标签School json:school
}// 反序列化-匿名字段 (默认字段冲突)
func TestUnMarshal() {jsonStr : {name:XiaoMing,name:北京大学,schoolAddress:北京海淀区}stu : Student{}err : json.Unmarshal([]byte(jsonStr), stu)if err ! nil {fmt.Println(err)return}fmt.Printf(反序列化结果%v, stu)fmt.Println()jsonStr2 : {name:XiaoMing,school:{name:北京大学,schoolAddress:北京海淀区}} stu2 : Student{}err json.Unmarshal([]byte(jsonStr2), stu2)if err ! nil {fmt.Println(err)return}fmt.Printf(2反序列化结果%v, stu2)fmt.Println()
}
func main() {TestUnMarshal()
}结果
反序列化结果{Name:北京大学 School:{Name: Address:}}
2反序列化结果{Name:XiaoMing School:{Name:北京大学 Address:北京海淀区}}3.4 匿名字段json总结
3.4.1 序列化
a. 匿名字段无标签 当匿名字段没有指定标签时序列化后的结构为同级,如{..:..,..} 当匿名属性和主属性的字段标签一样时序列化会忽略匿名属性的字段。 当匿名属性和主属性的字段标签不一样时序列化不忽略任何字段。
b. 匿名字段有标签 当匿名字段a指定标签时序列化后的结构为上下级,如{..:..,a:{xx:xx}} 匿名属性和主属性字段标签无论是否一致序列化都不会忽略任何字段。
4.2 反序列化
a. 匿名字段无标签 当匿名字段没有指定标签时可解析的JSON结构,为: {..:..,..} 当匿名属性和主属性的字段标签一样时会优先将值赋给主属性匿名属性为类型零值。 当匿名属性和主属性的字段标签不一样时会正常解析。
b. 匿名字段有标签 当匿名字段指定标签时可解析的JSON结构,为: {..:..,a:{xx:xx}} 匿名属性和主属性字段标签无论是否一致反序列化都能正常赋值。 当结构体中嵌套匿名结构体字段时在进行序列化和反序列时推荐为匿名字段加上json标签。