【go语言】结构体
一、type 关键字的用法
在 go 语言中,type 关键字用于定义新的类型,他可以用来定义基础类型、结构体类型、接口类型、函数类型等。通过 type 关键字,我们可以为现有类型创建新的类型别名或者自定义新的类型。
1.1 类型别名
使用 type
可以为现有类型创建一个新的别名,使得这个别名与原始类型具有相同的底层实现。
package mainimport "fmt"// 为 int 类型创建别名
type MyInt intfunc main() {var a MyInt = 10fmt.Println(a) // 输出 10fmt.Println(int(a)) // 输出 10
}
在这个例子中,MyInt
是 int
类型的一个别名,它与 int
类型完全相同,可以用作 int
类型的值。
1.2 定义结构体类型
type
也可以用来定义结构体类型,这种类型用于存储多个字段(数据)。
package mainimport "fmt"// 定义一个结构体类型
type Person struct {Name stringAge int
}func main() {// 创建一个 Person 类型的实例p := Person{Name: "Alice", Age: 30}fmt.Println(p) // 输出 {Alice 30}
}
1.3 定义函数类型
type
还可以用来定义函数类型,特别是在回调函数或接口方法中非常有用。
package mainimport "fmt"// 定义一个函数类型
type AddFunc func(a, b int) intfunc main() {// 使用函数类型var add AddFunc = func(a, b int) int {return a + b}fmt.Println(add(3, 5)) // 输出 8
}
在这个例子中,AddFunc
是一个函数类型,它定义了一个接收两个 int
参数并返回一个 int
类型结果的函数。
1.4 定义接口类型
type
还可以用来定义接口类型。接口类型定义了一组方法,任何类型只要实现了这些方法,就被认为实现了这个接口。
package mainimport "fmt"// 定义一个接口类型
type Speaker interface {Speak() string
}// 定义一个结构体类型
type Person struct {Name string
}// 实现接口方法
func (p Person) Speak() string {return "Hello, my name is " + p.Name
}func main() {var s Speaker = Person{Name: "Bob"}fmt.Println(s.Speak()) // 输出 Hello, my name is Bob
}
1.5 自定义类型(结构体或者基础类型)
可以使用 type
创建一个新的自定义类型,这种类型会与原类型相同,但可以拥有额外的行为。
package mainimport "fmt"// 定义一个新的自定义类型
type Celsius float64
type Fahrenheit float64// 定义转换函数
func CelsiusToFahrenheit(c Celsius) Fahrenheit {return Fahrenheit(c*9/5 + 32)
}func main() {var tempC Celsius = 25tempF := CelsiusToFahrenheit(tempC)fmt.Println(tempF) // 输出 77
}
type
关键字在 Go 语言中非常强大,能够用来:
- 为现有类型创建别名。
- 定义结构体、接口等自定义复合类型。
- 定义函数类型。
- 自定义类型(基于现有的基本类型或复合类型)。
这种灵活的类型定义方式使得 Go 语言的类型系统能够更好地支持多种编程风格,比如面向对象编程(通过接口)和函数式编程(通过函数类型)。
二、结构体的定义和初始化
在 Go 语言中,结构体(struct
)是一种复合数据类型,可以存储多个不同类型的数据。结构体用于将相关的变量组合在一起,通常用于表示现实世界中的对象。
2.1 结构体定义
结构体通过 type
关键字定义,结构体包含一组字段(field),每个字段都有一个名字和类型。
package mainimport "fmt"// 定义一个结构体类型
type Person struct {Name stringAge int
}func main() {// 创建结构体实例p := Person{Name: "Alice", Age: 30}fmt.Println(p) // 输出 {Alice 30}
}
2.2 结构体初始化
2.2.1 命名字段初始化
通过显式地指定字段名来初始化结构体。你可以指定某些字段,也可以省略某些字段(未指定字段会被默认初始化为零值)。
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {// 初始化时指定字段名p := Person{Name: "Bob", Age: 25}fmt.Println(p) // 输出 {Bob 25}
}
2.2.2 位置初始化
通过字段的顺序来初始化结构体,必须按照结构体字段的顺序传递参数。
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {// 按字段顺序初始化结构体p := Person{"Alice", 30}fmt.Println(p) // 输出 {Alice 30}
}
2.2.3 零值初始化
如果没有显式地初始化结构体,则会给字段赋予类型的零值(比如 string
的零值是空字符串 ""
,int
的零值是 0
)。
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {// 零值初始化var p Personfmt.Println(p) // 输出 { 0},Name 为空字符串,Age 为 0
}
2.2.4 使用 & 获取结构体的指针
可以通过 &
来获取结构体的指针,这样可以直接修改结构体的字段。
package mainimport "fmt"type Person struct {Name stringAge int
}func main() {// 创建结构体的指针p := &Person{Name: "Tom", Age: 40}fmt.Println(*p) // 输出 {Tom 40}// 通过指针修改字段p.Age = 41fmt.Println(*p) // 输出 {Tom 41}
}
三、匿名结构体
在 Go 语言中,匿名结构体是指没有定义类型名称的结构体。通常我们在需要快速定义结构体并使用时,会选择使用匿名结构体。匿名结构体适用于临时的、一时的结构体实例,而不需要为其命名类型。
3.1 匿名结构体的定义和使用
匿名结构体可以直接在代码中定义,并初始化其字段。它不需要像命名结构体那样定义类型名称。
package mainimport "fmt"func main() {// 创建一个匿名结构体并初始化person := struct {Name stringAge int}{Name: "Alice",Age: 25,}// 输出匿名结构体实例fmt.Println(person) // 输出:{Alice 25}
}
在上面的代码中:
- 我们定义了一个匿名结构体,结构体有两个字段:
Name
(string
类型)和Age
(int
类型)。 - 然后,我们通过字面量初始化该结构体,直接赋值给变量
person
。
3.2 匿名结构体的优缺点
优点:
- 简洁:匿名结构体非常适合于那些只需要一次性使用的结构数据,不需要为其单独定义类型。
- 灵活性:如果你只需要在特定函数或方法中使用一个临时结构体,不必为此创建一个新的类型,可以直接用匿名结构体。
- 局部使用:匿名结构体通常用于局部变量,使用范围小,适合不需要重复引用的场景。
缺点:
- 可读性差:当匿名结构体嵌套或者与其他结构体一起使用时,可能会使代码的可读性下降,尤其是没有类型名称的情况下。
- 类型安全问题:匿名结构体缺少类型名称,因此不能像命名结构体那样明确区分不同类型的结构体。多个匿名结构体之间不能直接进行赋值或比较,除非它们完全相同。
3.3 匿名结构体和命名结构体的比较
- 命名结构体:在代码中定义一个类型名,可以重复使用,也能在其他地方引用。
- 匿名结构体:没有类型名称,只能在当前代码中使用,适合临时数据。
四、结构体嵌套
在 Go 语言中,结构体嵌套是指在一个结构体中嵌套另一个结构体作为字段。通过结构体嵌套,可以将多个结构体组合在一起,从而形成更复杂的数据结构。这使得结构体能够具备更高的复用性和灵活性。
4.1 结构体嵌套的基本概念
结构体嵌套可以让一个结构体包含另一个结构体作为它的字段,或者嵌套多个结构体。嵌套结构体通常用于描述包含子部分的数据模型。例如,表示一个 Person
可能有 Address
作为嵌套的字段。
4.2 结构体嵌套的匿名嵌套
在 Go 语言中,结构体可以以匿名结构体的方式嵌套。这使得代码更加简洁。匿名结构体嵌套时,不需要在内嵌结构体中声明字段类型的名称。
package mainimport "fmt"// 定义 Person 结构体,嵌套匿名结构体
type Person struct {Name stringAge intAddress struct {City stringState stringZipCode string} // 匿名结构体
}func main() {// 创建并初始化 Person 结构体p := Person{Name: "Bob",Age: 40,}p.Address.City = "Los Angeles"p.Address.State = "CA"p.Address.ZipCode = "90001"fmt.Println(p) // 输出:{Bob 40 {Los Angeles CA 90001}}
}
4.3 结构体嵌套的用途
结构体嵌套的常见用途包括:
- 表示复杂的数据模型:通过嵌套结构体来表示一对多或多对多的关系。
- 代码复用:将共用的结构体嵌套在其他结构体中,避免重复代码。
- 提升可维护性:通过结构体嵌套,可以将不同的逻辑模块拆分成独立的结构体,增强代码的可读性和维护性。
五、结构体定义方法
在 Go 语言中,结构体(struct)是一种数据类型,可以用来组合不同类型的数据,表示一个实体。结构体的定义方法有两种:一种是使用 type
关键字定义,另一种是通过 struct
关键字直接声明。下面我会详细介绍这两种方法。
5.1 使用 type
关键字定义结构体
通过 type
关键字,可以为结构体类型创建一个新的名称。定义后的结构体类型可以用来声明变量、函数参数和返回值等。
package mainimport "fmt"// 使用 type 定义结构体
type Person struct {Name stringAge int
}func main() {// 创建结构体实例并初始化p := Person{Name: "Alice",Age: 30,}fmt.Println(p) // 输出:{Alice 30}
}
5.2 使用匿名结构体定义
除了通过 type
定义结构体外,还可以直接在变量声明时定义匿名结构体类型。这种方式适用于那些不需要多次使用该结构体类型的情况。
package mainimport "fmt"func main() {// 直接定义匿名结构体p := struct {Name stringAge int}{Name: "Bob",Age: 25,}fmt.Println(p) // 输出:{Bob 25}
}
5.3 结构体定义中字段的标签(Tag)
Go 的结构体字段可以附加标签,标签通常用于提供元数据或在反射中使用。例如,数据库、JSON 或 XML 编码时,字段标签可以用来指定如何处理字段的名称或格式。
package mainimport ("fmt""reflect"
)// 定义一个结构体,使用字段标签
type Person struct {Name string `json:"name"`Age int `json:"age"`
}func main() {p := Person{Name: "Alice",Age: 30,}// 使用反射查看结构体标签t := reflect.TypeOf(p)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Println(field.Name, field.Tag)}
}
六、结构体标签
在 go 语言中,结构体标签是附加到结构体字段上的元数据,用于指定一些额外的信息。这些标签通常用于在序列化、反序列化、数据库映射等过程中对字段进行特别的处理。标签的主要用途是为第三方库提供额外的配置信息,通常这些标签不直接影响程序的逻辑,但是他们会影响如何处理结构体的字段。
6.1 标签的基本语法
结构体标签由反引号包裹,通常位于结构体字段声明的后面。标签的格式为:tagKey:"tagValue"
。
type Person struct {Name string `json:"name"`Age int `json:"age"`
}
在这个例子中,Name
字段和 Age
字段分别有 json
标签,指示它们在 JSON 编解码时使用的字段名。
6.2 常见的结构体标签用途
6.2.1 JSON 标签
Go 的标准库 encoding/json
使用结构体标签来控制 JSON 编解码的行为。
json
标签 用于指定结构体字段在 JSON 中的键名。omitempty
: 如果字段值为空,则忽略该字段(用于 JSON 编解码时)。-
: 忽略该字段,不进行 JSON 编解码。
type Person struct {Name string `json:"name"`Age int `json:"age,omitempty"`Email string `json:"-"`
}
在这个例子中,Email
字段不会被序列化为 JSON,因为它的标签是 json:"-"
。如果 Age
为零值(0),它会被忽略。
6.2.2 XML 标签
Go 的标准库 encoding/xml
使用 xml
标签来指定结构体字段在 XML 中的元素名称。
type Person struct {Name string `xml:"name"`Age int `xml:"age"`
}
在这个例子中,Name
和 Age
字段将被编码为 XML 元素 <name>
和 <age>
。
6.2.3 数据库标签
GORM 是 Go 的一个流行 ORM 库,它使用结构体标签来指定字段与数据库表字段之间的映射关系。
type Person struct {ID int `gorm:"primary_key"`Name string `gorm:"column:name"`Age int `gorm:"column:age"`
}
这里,gorm
标签指定了字段如何映射到数据库列,例如 ID
字段是主键,Name
字段映射为 name
列。
6.2.4 自定义标签
除了标准的 JSON、XML 和数据库标签外,开发者可以创建自定义标签来满足特定需求,比如表单验证、日志记录等。
type User struct {Username string `validate:"required"`Password string `validate:"min=8"`
}
在这个例子中,validate
标签可以用于执行字段值验证。
6.3 读取结构体标签
Go 提供了反射(reflect
)功能,可以动态读取结构体的标签。这对于构建通用框架或库非常有用。
package mainimport ("fmt""reflect"
)type Person struct {Name string `json:"name" xml:"name"`Age int `json:"age" xml:"age"`
}func main() {p := Person{Name: "Alice", Age: 30}// 使用反射获取字段标签t := reflect.TypeOf(p)for i := 0; i < t.NumField(); i++ {field := t.Field(i)fmt.Printf("Field: %s, JSON Tag: %s, XML Tag: %s\n", field.Name, field.Tag.Get("json"), field.Tag.Get("xml"))}
}
6.4 多个标签
一个字段可以有多个标签,它们之间用空格分隔。在处理这些标签时,每个库会按照它们的定义来解析标签。
type Person struct {Name string `json:"name" xml:"name" gorm:"column:name"`Age int `json:"age" xml:"age"`
}
6.5 标签的常见选项
标签的具体内容取决于你使用的库和框架。以下是一些常见标签选项:
-
json
标签:json:"name"
: 指定 JSON 中的字段名。json:"-"
: 忽略该字段。json:"omitempty"
: 如果字段值为零值(如""
或0
),则忽略该字段。
-
gorm
标签(用于数据库映射):gorm:"primary_key"
: 标明字段是主键。gorm:"not null"
: 字段不能为空。gorm:"default:value"
: 设置字段的默认值。
-
xml
标签:xml:"name"
: 指定 XML 中的元素名。
6.6 结构体标签的作用
标签主要作用是为第三方库提供额外的信息,帮助它们在处理结构体时遵循某些规则。常见的使用场景包括:
- JSON 或 XML 编解码时确定字段名的映射。
- 数据库 ORM 框架中映射字段到数据库列。
- 表单验证框架中使用标签来标识哪些字段需要验证。
- 日志框架中用于标识哪些字段需要被记录。
相关文章:

【go语言】结构体
一、type 关键字的用法 在 go 语言中,type 关键字用于定义新的类型,他可以用来定义基础类型、结构体类型、接口类型、函数类型等。通过 type 关键字,我们可以为现有类型创建新的类型别名或者自定义新的类型。 1.1 类型别名 使用 type 可以为…...

Spring Boot是什么及其优点
简介 Spring Boot是基于Spring框架开发的全新框架,其设计目的是简化Spring应用的初始化搭建和开发过程。 Spring Boot整合了许多框架和第三方库配置,几乎可以达到“开箱即用”。 优点 可快速构建独立的Spring应用。 直接嵌入Tomcat、Jetty和Underto…...

谷氨酸:大脑功能的多面手
标题:谷氨酸:大脑功能的多面手 文章信息摘要: 谷氨酸是大脑中最主要的兴奋性神经递质,参与了90%以上的神经元激活,在蛋白质合成、味觉(鲜味)以及神经可塑性中发挥重要作用。它与GABA、多巴胺等…...

SpringCloudGateWay和Sentinel结合做黑白名单来源控制
假设我们的分布式项目,admin是8087,gateway是8088,consumer是8086 我们一般的思路是我们的请求必须经过我们的网关8088然后网关转发到我们的分布式项目,那我要是没有处理我们绕过网关直接访问项目8087和8086不也是可以࿱…...

HTML新春烟花
系列文章 序号目录1HTML满屏跳动的爱心(可写字)2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐5HTML蓝色爱心射线6HTML跳动的爱心(简易版)7HTML粒子爱心8HTML蓝色动态爱心9HTML跳动的爱心(双心版)10…...

【Elasticsearch】中数据流需要配置索引模板吗?
是的,数据流需要配置索引模板。在Elasticsearch中,数据流(Data Streams)是一种用于处理时间序列数据的高级结构,它背后由多个隐藏的索引组成,这些索引被称为后备索引(Backing Indices࿰…...

Git进阶之旅:Git 配置信息 Config
Git 配置级别: 仓库级别:local [ 优先级最高 ]用户级别:global [ 优先级次之 ]系统级别:system [ 优先级最低 ] 配置文件位置: git 仓库级别对应的配置文件是当前仓库下的 .git/configgit 用户级别对应的配置文件时用…...

buu-pwn1_sctf_2016-好久不见29
这个也是栈溢出,不一样的点是,有replace替换,要输入0x3c字符(60),Iyou 所以,20个I就行,找后面函数 输出提示信息,要求用户输入关于自己的信息。 使用fgets函数从标准输入…...

ES2021+新特性、常用函数
一、ES2021新特性 ES2021 数字分隔符 let num 1234567 let num2 1_234_567 Promise.any 与 Promise.all 类似,Promise.any 也接受一个 Promise 的数组。当其中任何一个 Promise 完成(fullfill)时,就返回那个已经有完成值的 …...

STM32——LCD
一、引脚配置 查看引脚 将上述引脚都设置为GPIO_Output 二、导入驱动文件 将 LCD 驱动的 Inc 以及 Src 中的 fonts.h,lcd.h 和 lcd.c 导入到自己工程的驱动文件中。 当然,后面 lcd 的驱动学习可以和 IMX6U 一块学。 三、LCD函数 void LCD_Clear(u16 Color); 功能…...

【redis进阶】分布式锁
目录 一、什么是分布式锁 二、分布式锁的基础实现 三、引入过期时间 四、引入校验 id 五、引入lua 六、引入 watch dog (看门狗) 七、引入 Redlock 算法 八、其他功能 redis学习🥳 一、什么是分布式锁 在一个分布式的系统中,也会涉及到多个节点访问同一…...

园区管理系统如何提升企业核心竞争力与资产管理智能化水平
内容概要 在当今快节奏的商业环境中,园区管理系统正成为企业的重要合作伙伴,尤其在工业园、产业园、物流园、写字楼和公寓等多种类型的物业管理中。这个系统不仅仅是一个管理工具,它还是提升企业运营效率和核心竞争力的关键因素。通过智能化…...

AI大模型开发原理篇-3:词向量和词嵌入
简介 词向量是用于表示单词意义的向量, 并且还可以被认为是单词的特征向量或表示。 将单词映射到实向量的技术称为词嵌入。在实际应用中,词向量和词嵌入这两个重要的NLP术语通常可以互换使用。它们都表示将词汇表中的单词映射到固定大小的连续向量空间中…...

高精度算法:高精度减法
P2142 高精度减法 - 洛谷 | 计算机科学教育新生态 我们两个整数一定要是大数减去小数,所以这个点我们需要特判一下,那我们两个字符串表示的整型怎么判断大小呢,我们字典序比较大小和真实的数字比较大小是一样的,比如我们的‘21’…...

Java创建项目准备工作
新建项目 新建空项目 每一个空项目创建好后都要检查jdk版本 检查SDK和语言级别——Apply——OK 检查当前项目的Maven路径,如果已经配置好全局,就是正确路径不用管 修改项目字符集编码,将所有编码都调整为UTF-8 创建Spingboot工程 创建Spring…...

基于STM32的智能宠物喂食器设计
目录 引言系统设计 硬件设计软件设计 系统功能模块 定时喂食模块远程控制与视频监控模块食物存量检测与报警模块语音互动与用户交互模块数据记录与智能分析模块 控制算法 定时与手动投喂算法食物存量检测与低存量提醒算法数据记录与远程反馈算法 代码实现 喂食控制代码存量检测…...

在线课堂小程序设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...

为AI聊天工具添加一个知识系统 之77 详细设计之18 正则表达式 之5
本文要点 昨天讨论了 本项目(AI聊天工具添加一个知识系统)中正则表达式模板的设计中可能要考虑到的一些问题(讨论到的内容比较随意,暂时无法确定 那些考虑 是否 应该是正则表达式模板设计要考虑的以及 是否完整)。今天…...

【Elasticsearch】 索引模板 ignore_missing_component_templates
解释 ignore_missing_component_templates 配置 在Elasticsearch中,ignore_missing_component_templates 是一个配置选项,用于处理索引模板中引用的组件模板可能不存在的情况。当您创建一个索引模板时,可以指定一个或多个组件模板࿰…...

Github 2025-01-29 C开源项目日报 Top10
根据Github Trendings的统计,今日(2025-01-29统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10C++项目1Assembly项目1Go项目1我的电视 - 安卓电视直播软件 创建周期:40 天开发语言:CStar数量:649 个Fork数量:124 次关注人数:64…...

文件上传2
BUUCTF 你传你🐎呢 先上传.htaccess 修改格式 即可上传成功 返回上传图片格式的木马 用蚁剑连接 5ecf1cca-59a1-408b-b616-090edf124db5.node5.buuoj.cn:81/upload/7d8511a847edeacb5385299396a96d91/rao.jpg 即可得到flag [GXYCTF2019]BabyUpload...

Unity敌人逻辑笔记
写ai逻辑基本上都需要状态机。因为懒得手搓状态机,所以选择直接用动画状态机当逻辑状态机用。 架构设计 因为敌人的根节点已经有一个animator控制动画,只能增加一个子节点AI,给它加一个animator指向逻辑“动画”状态机。还有一个脚本&#…...

高级编码参数
1.跳帧机制 参考资料:frameskipping-hotedgevideo 跳帧机制用于优化视频质量和编码效率。它通过选择性地跳过某些帧并使用参考帧来预测和重建视频内容,从而减少编码所需的比特率,同时保持较高的视频质量。在视频编码过程中,如果…...

DeepSeek-R1:通过强化学习激励大型语言模型(LLMs)的推理能力
摘要 我们推出了第一代推理模型:DeepSeek-R1-Zero和DeepSeek-R1。DeepSeek-R1-Zero是一个未经监督微调(SFT)作为初步步骤,而是通过大规模强化学习(RL)训练的模型,展现出卓越的推理能力。通过强…...

leetcode——合并K个有序链表(java)
给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例 1: 输入:lists [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下&#…...

【Valgrind】安装报错: 报错有未满足的依赖关系: libc6,libc6-dbg
Valgrind 内存泄漏检测工具安装 安装 sudo apt install valgrind官方上也是如此 但是在我的系统(debian12)上却失败了: 报错有未满足的依赖关系: libc6 : 破坏: valgrind (< 1:3.19.0-1~) 但是 1:3.16.1-1 正要被安装 libc6-dbg : 依赖…...

vue3和vue2的区别有哪些差异点
Vue3 vs Vue2 主要差异对比指南 官网 1. 核心架构差异 1.1 响应式系统 Vue2:使用 Object.defineProperty 实现响应式 // Vue2 响应式实现 Object.defineProperty(obj, key, {get() {// 依赖收集return value},set(newValue) {// 触发更新value newValue} })Vue3…...

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(六)(完结)
Understanding Diffusion Models: A Unified Perspective(六)(完结) 文章概括指导(Guidance)分类器指导无分类器引导(Classifier-Free Guidance) 总结 文章概括 引用: …...

NPM 使用介绍
NPM 使用介绍 引言 NPM(Node Package Manager)是Node.js生态系统中的一个核心工具,用于管理JavaScript项目的依赖包。无论是开发一个小型脚本还是构建大型应用程序,NPM都能极大地提高开发效率。本文将详细介绍NPM的使用方法,包括安装、配置、依赖管理、包发布等,帮助您…...

http3网站的设置(AI不会配,得人工配)
堡塔PHP项目中配置nginx1.26.0设置http3协议 # 文件所在服务器中的路径 /www/server/nginx/conf/nginx.confuser www www; worker_processes auto; error_log /www/wwwlogs/nginx_error.log crit; pid /www/server/nginx/logs/nginx.pid; worker_rlimit_nofile 512…...