【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
}

       在这个例子中,MyIntint 类型的一个别名,它与 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 语言中非常强大,能够用来:

  1. 为现有类型创建别名
  2. 定义结构体、接口等自定义复合类型
  3. 定义函数类型
  4. 自定义类型(基于现有的基本类型或复合类型)。

       这种灵活的类型定义方式使得 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}
}

在上面的代码中:

  • 我们定义了一个匿名结构体,结构体有两个字段:Namestring 类型)和 Ageint 类型)。
  • 然后,我们通过字面量初始化该结构体,直接赋值给变量 person

3.2 匿名结构体的优缺点

优点:
  1. 简洁:匿名结构体非常适合于那些只需要一次性使用的结构数据,不需要为其单独定义类型。
  2. 灵活性:如果你只需要在特定函数或方法中使用一个临时结构体,不必为此创建一个新的类型,可以直接用匿名结构体。
  3. 局部使用:匿名结构体通常用于局部变量,使用范围小,适合不需要重复引用的场景。
缺点:
  1. 可读性差:当匿名结构体嵌套或者与其他结构体一起使用时,可能会使代码的可读性下降,尤其是没有类型名称的情况下。
  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"`
}

在这个例子中,NameAge 字段将被编码为 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 框架中映射字段到数据库列。
  • 表单验证框架中使用标签来标识哪些字段需要验证。
  • 日志框架中用于标识哪些字段需要被记录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9525.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hive安装教程

Hive安装教程 文章目录 Hive安装教程写在前面安装下载安装部署安装Hive启动并使用Hive MySQL安装检查当前系统是否安装过MySQL安装初始化数据库 Hive元数据配置到MySQL拷贝驱动配置Metastore到MySQL再次启动Hive 写在前面 Linux版本&#xff1a;CentOS7.5Hive版本&#xff1a;…

大屏 UI 设计风格的未来趋势

在科技飞速革新的时代&#xff0c;大屏设备的应用领域不断拓展&#xff0c;从城市的智能交通指挥中心&#xff0c;到商场的互动广告大屏&#xff0c;再到家庭的超大尺寸智能电视&#xff0c;大屏已然成为信息展示与交互的关键载体。大屏 UI 设计风格也随之不断演变&#xff0c;…

元素的显示与隐藏

display显示隐藏visibility显示隐藏overflow溢出显示隐藏 display属性 visibility属性 overflow溢出

Unity游戏(Assault空对地打击)开发(1) 创建项目和选择插件

目录 前言 创建项目 插件导入 地形插件 前言 这是游戏开发第一篇&#xff0c;进行开发准备。 创作不易&#xff0c;欢迎支持。 我的编辑器布局是【Tall】&#xff0c;建议调整为该布局&#xff0c;如下。 创建项目 首先创建一个项目&#xff0c;过程略&#xff0c;名字请勿…

网络工程师 (7)进程管理

一、进程相关的概念 &#xff08;一&#xff09;定义 进程&#xff08;Process&#xff09;是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配和调度的基本单位&#xff0c;也是操作系统结构的基础。进程是程序的一次执行实例&#xff0c;具有动…

使用CSS实现一个加载的进度条

文章目录 使用CSS实现一个加载的进度条一、引言二、步骤一&#xff1a;HTML结构与CSS基础样式1、HTML结构2、CSS基础样式 三、步骤二&#xff1a;添加动画效果1、使用CSS动画2、结合JavaScript控制动画 四、使用示例五、总结 使用CSS实现一个加载的进度条 一、引言 在现代网页…

ios swift画中画技术尝试

继上篇&#xff1a;iOS swift 后台运行应用尝试失败-CSDN博客 为什么想到画中画&#xff0c;起初是看到后台模式里有一个picture in picture&#xff0c;去了解了后发现这个就是小窗口视频播放&#xff0c;方便用户执行多任务。看小窗口视频的同时&#xff0c;可以作其他的事情…

论文阅读(二):理解概率图模型的两个要点:关于推理和学习的知识

1.论文链接&#xff1a;Essentials to Understand Probabilistic Graphical Models: A Tutorial about Inference and Learning 摘要&#xff1a; 本章的目的是为没有概率图形模型背景或没有深入背景的科学家提供一个高级教程。对于更熟悉这些模型的读者&#xff0c;本章将作为…

【C++】特殊类设计

目录 一、请设计一个类&#xff0c;不能被拷贝二、请设计一个类&#xff0c;只能在堆上创建对象三、请设计一个类&#xff0c;只能在栈上创建对象四、请设计一个类&#xff0c;不能被继承五、请设计一个类&#xff0c;只能创建一个对象(单例模式)5.1 饿汉模式5.2 懒汉模式 结尾…

SSM开发(七) MyBatis解决实体类(model)的字段名和数据库表的列名不一致方法总结(四种方法)

目录 方法一: 使用@Results和@Result注解(注解方式) 方法二:修改 SQL 查询语句中的别名(注解方式) 方法三: 全局配置别名或结果映射(resultMap,XML配置方式) 方法四:使用@Column注解 在MyBatis中,如果你希望使用注解的方式来操作数据库,但又遇到实体类中的…

USB 3.1-GL3510-52芯片原理图设计

USB 3.1-GL3510-52芯片原理图设计 端口功能与兼容性物理层集成与性能电源相关特性充电功能其他特性原理图接口防护ESD 保护要求 GL3510-52是一款由Genesys Logic&#xff08;创惟科技&#xff09;研发的USB转换芯片&#xff0c;具有以下特点&#xff1a; 端口功能与兼容性 它…

LeetCode热题100中 17. 20. 53. 78. 215.

17.电话号码的字母组合&#xff1a; 题目描述&#xff1a; 实现思路&#xff1a; 将回溯过程抽象成树结构&#xff0c;每个叶子节点作为结果的一部分。 我们定义一个数组map&#xff0c;它的下标表示输入的数字所对应的字母&#xff0c;先对特殊情况进行处理&#xff1a;1.输…

高级编码参数

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

内网穿透实现MC联机

目录 内网穿透下载安装服务端&#xff08;你&#xff09;启动网络启动 MC 客户端&#xff08;你的朋友&#xff09; 放寒假了&#xff0c;想和同学玩mc&#xff0c;但是没有服务器怎么办呢&#xff1f;这就不得不提到内网穿透技术了。 注&#xff1a;本文参考视频&#xff1a;…

【每日一A】2015NOIP真题 (二分+贪心) python

题目概述 在起点和终点之间有n个石头&#xff0c;移除某些&#xff08;不超过m个&#xff09;石头后&#xff0c;让石头间的距离最大。 求石头间的最短距离d的最大值 跳石头 点此跳转 https://www.lanqiao.cn/problems/364/learning/?page1&first_category_id1&status…

获取snmp oid的小方法1(随手记)

snmpwalk遍历设备的mib # snmpwalk -v <SNMP version> -c <community-id> <IP> . snmpwalk -v 2c -c test 192.168.100.201 .根据获取的值&#xff0c;找到某一个想要的值的oid # SNMPv2-MIB::sysName.0 STRING: test1 [rootzabbix01 fonts]# snmpwalk -v…

FreeRTOS从入门到精通 第十四章(队列集)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、队列集简介 1、队列集概述 &#xff08;1&#xff09;一个队列只允许任务间传递的消息为同一种数据类型&#xff0c;如果需要在任务间传递不同数据类型的消息时&#xff0c;那么就可以…

Spring MVC 综合案例

目录 一. 加法计算器 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 3. 服务器端代码 4. 运行测试 二. 用户登录 1. 准备工作 2. 约定前后端交互接口 需求分析 接口定义 (1) 登录界面接口 (2) 首页接口 3. 服务器端代码 4. 运行测试 三. 留言板 1. 准备…

Edge-TTS在广电系统中的语音合成技术的创新应用

Edge-TTS在广电系统中的语音合成技术的创新应用 作者&#xff1a;本人是一名县级融媒体中心的工程师&#xff0c;多年来一直坚持学习、提升自己。喜欢Python编程、人工智能、网络安全等多领域的技术。 摘要 随着人工智能技术的快速发展&#xff0c;文字转语音&#xff08;Te…

36、【OS】【Nuttx】OSTest分析(2):环境变量测试

背景 2025.1.29 蛇年快乐&#xff01; 接之前wiki 35、【OS】【Nuttx】OSTest分析&#xff08;1&#xff09;&#xff1a;stdio测试&#xff08;五&#xff09; 已经分析完了第一个测试项&#xff0c;输入输出端口测试&#xff0c;接下来分析下环境变量测试&#xff0c;也比较…