Go语言匿名字段使用与注意事项
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:"xx" | key=xx | 
| 无标签 | key=结构体原属性字段 | 
| 有标签, json:"-" | 会被忽略,不参与序列化 | 
| 有标签, json:"xxx,omitempty" | 代表该字段为空值时,会被忽略。其中 xxx可以省略,,不可以省略。如: json:",omitempty" | 
| 有标签, json:"xxx,string" | 代表输出类型会转化为字符串。其中 xxx也可以省略它只适用于字符串、浮点数、整数类型的字段 | 
3.1 代码示例
package mainimport ("encoding/json""fmt"
)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.Name,Json标签不一致。
package mainimport ("encoding/json""fmt"
)// 学校
type School struct {Name    string `json:"schoolName"`Address 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.Name,Json标签一致,都是 json:"name"。
package mainimport ("encoding/json""fmt"
)// 学校
type School struct {Name    string `json:"name"`Address 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/json""fmt"
)// 学校
type School struct {Name    string `json:"name"`Address 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/json""fmt"
)// 学校
type School struct {Name    string `json:"schoolName"`Address 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/json""fmt"
)// 学校
type School struct {Name    string `json:"name"`Address 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/json""fmt"
)// 学校
type School struct {Name    string `json:"name"`Address 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标签。

相关文章:
 
Go语言匿名字段使用与注意事项
1. 定义 Go语言支持一种特殊的字段只需要提供类型而不需要写字段名的字段,称之为匿名字段或者嵌套字段。 所谓匿名字段实际上是一种结构体嵌套的方式,所以也可以称作嵌套字段。 这种方式可以实现组合复用,即通过匿名字段,结构体…...
2024最新!!Java后端面试题(2)看这一篇就够了
hello uu们 感谢收看!!!!我最近听了一首歌《21》,真的很感慨,马上步入20的我也感觉时间真的飞快...望大家都能过上理想的生活,不负内心的所托...现在口语化更新答案,让大家更加模拟的…...
 
超好用的10款视频剪辑软件,从入门到精通
视频剪辑软件哪款比较好呢?无论是专业制作团队、自媒体创作者,还是家庭用户,一款好用的视频剪辑软件都能极大地提升创作效率和作品质量。以下是十款备受推崇的视频剪辑软件,分别从适用人群、易用程度和功能特点进行介绍。 1.影忆…...
python股票因子,交易所服务器宕机,量化交易程序怎么应对
炒股自动化:申请官方API接口,散户也可以 python炒股自动化(0),申请券商API接口 python炒股自动化(1),量化交易接口区别 Python炒股自动化(2):获取…...
 
瑞芯微RK3566鸿蒙开发板Android11修改第三方输入法为默认输入法
本文适用于触觉智能所有支持Android11系统的开发板修改第三方输入法为默认输入法。本次使用的是触觉智能的Purple Pi OH鸿蒙开源主板,搭载了瑞芯微RK3566芯片,类树莓派设计,是Laval官方社区主荐的一款鸿蒙开发主板。 一、安装输入法并查看输入…...
使用nest+typeorm框架写数据库导致mysql的binlog暴增记录
这 两天用nesttypeorm写了一个商城,上线后mysql日志binlog两天就达到了10几个G,排查结果如下: 有个功能是定时遍历所有未签收的订单,看看是否到了自动签收时间,如果到了,就把订单状态设置成已签收。 代码…...
 
组合逻辑元件与时序逻辑元件
组合逻辑元件和时序逻辑元件都是数字电路中的基本构建块,但它们在功能和结构上存在显著差异。 1. 组合逻辑元件: 内容: 组合逻辑元件的输出仅取决于当前的输入,而与之前的输入无关。 它们没有记忆功能。 常见的组合逻辑元件包括: 与门 (AND…...
 
天龙八部怀旧单机微改人面桃花+安装教程+GM工具+虚拟机一键端
今天给大家带来一款单机游戏的架设:天龙八部怀旧单机微改人面桃花。 另外:本人承接各种游戏架设(单机联网) 本人为了学习和研究软件内含的设计思想和原理,带了架设教程仅供娱乐。 教程是本人亲自搭建成功的…...
docker管理
拉取容器镜像 docker pull 镜像名:镜像版本查看镜像 docker images查看容器列表 # 查看正在运行的容器 docker ps # 查看全部的容器(包括停止的容器) docker ps -a进入容器 docker exec -it 容器id /bin/bash停止容器 docker stop 容器id运行容器 docker start 容器id删除…...
 
electron教程(三)窗口设置
在main.js文件中,创建窗口时会设置窗口的大小,其实还有很多其他属性,可以根据实际需求选择设置,但部分属性存在局限性,官网也有明确告知:自定义窗口 | Electron (electronjs.org) 项目文件目录如下&#x…...
 
图像增强论文精读笔记-Deep Retinex Decomposition for Low-Light Enhancement(Retinex-Net)
1. 论文基本信息 论文标题:Deep Retinex Decomposition for Low-Light Enhancement 作者:Chen Wei等 发表时间和期刊:2018;BMVC 论文链接:https://arxiv.org/abs/1808.04560 2. 研究背景和动机 低光照条件下拍摄的…...
 
2024年配置YOLOX运行环境+windows+pycharm24.0.1+GPU
1.配置时间2024/9/25 2.Anaconda-python版本3.7,yolox版本0.2.0 YOLOX网址: https://github.com/Megvii-BaseDetection/YOLOX 本人下载的这个版本 1.创建虚拟环境 conda create -n yolox37 python37 激活 conda activate yolox37 2.安装Pytorch cuda等&…...
 
vue-i18n在使用$t时提示类型错误
1. 问题描述 Vue3项目中,使用vue-i18n,在模版中使用$t时,页面可以正常渲染,但是类型报错。 相关依赖版本如下: "dependencies": {"vue": "^3.4.29","vue-i18n": "^9.1…...
大厂面试真题-什么是CAS单点登录?什么原理
CAS(Central Authentication Service,中央认证服务)单点登录(SSO,Single Sign-On)的原理主要基于统一的认证机制和票据验证过程,使得用户只需在多个相互信任的应用系统中登录一次,即…...
 
用Java提取PDF表格到文本、CSV、Excel工作表
如何精准地提取PDF格式中嵌入的表格数据,并将其无缝转换为更加易于分析和操作的形式,如纯文本、CSV文件或Excel工作表,是一项重要的文档处理技巧。使用Java,我们可以简单地实现这一过程。本文将介绍如何利用Java从PDF文档提取表格…...
OpenCV视频I/O(10)视频采集类VideoCapture之从视频流中检索一帧图像函数 retrieve()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 解码并返回已抓取的视频帧。 cv::VideoCapture::retrieve() 是 VideoCapture 类的一个成员函数,用于从视频流中检索一帧图像。 retr…...
 
【RocketMQ】SpringBoot整合RocketMQ
🎯 导读:本文档详细介绍了如何在Spring Boot应用中集成Apache RocketMQ,并实现消息生产和消费功能。首先通过创建消息生产者项目,配置POM文件引入RocketMQ依赖,实现同步消息发送,并展示了如何发送普通字符串…...
mysql replace无法替换空格?如何解决
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互…...
 
Redis篇(环境搭建)
目录 一、安装包 1. Windows版下载地址 2. Linux版下载地址 二、安装Redis 1. 在Linux中安装Redis 2. 在Windows中安装Redis 3. 细节问题 三、Redis服务启动 1. 默认启动 2. 指定配置启动 3. 开机自启 四、Redis服务停止 1. Linux系统中启动和停止Redis 2. Window…...
 
【C++题目】7.双指针_和为 s 的两个数字
文章目录 题目链接:题目描述:解法C 算法代码:图解 题目链接: LCR 179.查找总价格为目标值的两个商品 题目描述: 解法 解法一(暴力解法,会超时) 两层 for 循环列出所有两个数字的组合…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
 
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
 
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
 
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
 
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
 
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
 
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
