找回密码
 立即注册
首页 业界区 业界 Golang基础笔记五之结构体

Golang基础笔记五之结构体

撙仿 2025-6-26 21:35:45
本文首发于公众号:Hunter后端
原文链接:Golang基础笔记五之结构体
本篇笔记介绍 Golang 中的结构体。
在 Go 中,结构体是一种用户自定义的数据类型,可以将不同类型的数据组合在一起。
以下是本篇笔记目录:

  • 结构体的定义和使用
  • 嵌套结构体
  • 创建结构体递归结构
  • 结构体标签
1、结构体的定义和使用

结构体定义的基本语法如下:
  1. type 结构体名称 struct{
  2.     field1 type
  3.     field2 type
  4. }
复制代码
我们可以先创建一个 struct:
  1. type Person struct {
  2.     Name string
  3.     Age  int
  4. }
复制代码
下面介绍几种方式来实例化结构体:
1. 使用结构体字面量初始化

使用结构体字面量初始化结构体变量,在创建结构体变量时,将字段值直接赋给结构体的字段。
其语法如下:
  1. person := Person{Name: "Alice", Age: 30}
  2. fmt.Println(person)
复制代码
在这里,如果有字段没有赋值,那么这个字段的值就是该类型的零值。
2. 按字段顺序初始化

我们可以在初始化的时候不指定字段,那么它会按照结构体中的字段顺序进行赋值:
  1. person := Person{"Alice", 30}
  2. fmt.Println(person)
复制代码
但是这个操作有个问题,就是结构体中的全部字段都需要赋值。
3. 使用 new 函数创建结构体指针

可以使用 new() 函数创建一个结构体,但是注意,其返回值是对应结构体的指针:
  1. var person *Person = new(Person)
  2. person.Age = 1
  3. person.Name = "Hunter"
复制代码
2、嵌套结构体

结构体可以嵌套在另一个结构体里,这个就是嵌套结构体。
1. 匿名嵌套

在嵌套的时候如果直接嵌套不指定字段名,这个就叫匿名嵌套,比如下面的示例:
  1. type Address struct {
  2.     City string
  3. }
  4. type Person struct {
  5.     Name string
  6.     Age  int
  7.     Address
  8. }
复制代码
这里没有给 Address 指定字段名,所以这个 Address 就是一个匿名字段。
以下是一个初始化的例子:
  1. person := Person{
  2.     Name: "Hunter",
  3.     Age:  18,
  4.     Address: Address{
  5.         City: "Beijing",
  6.     },
  7. }
复制代码
使用匿名嵌套,我们可以直接访问到嵌套的结构体的字段:
  1. fmt.Println(person.City)
复制代码
这里 City 是 Addree 结构体的字段,但因为是匿名嵌套,所以可以直接访问到。
当然,也可以通过 Address 结构体进行访问:
  1. fmt.Println(person.Address.City)
复制代码
2. 具名嵌套

如果嵌套的时候显式指定字段名,就叫具名嵌套,比如:
  1. type Company struct {
  2.     CompanyName string
  3. }
  4. type Person struct {
  5.     Name string
  6.     Age  int
  7.     CompanyInfo Company
  8. }
复制代码
这里为了以示区分,给 Company 结构体的字段名设为 CompanyInfo,其初始化的方式还是类似的:
  1. person := Person{
  2.     Name: "Hunter",
  3.     Age:  18,
  4.     CompanyInfo: Company{
  5.         CompanyName: "ACompany",
  6.     },
  7. }
复制代码
而如果要访问到嵌套的结构体的字段,则需要通过 CompanyInfo 进行访问:
  1. fmt.Println(person.CompanyInfo.CompanyName)
复制代码
3、创建结构体递归结构

我们可以通过结构体嵌套自己来形成递归结构,但是嵌套的类型需要是自身结构体的指针。
下面介绍一下使用结构体来创建链表和二叉树。
1. 链表

链表的结构体如下:
  1. type ListNode struct {
  2.     Val  int
  3.     Next *ListNode
  4. }
复制代码
接下来创建一个链表,并打印节点内容:
  1. head := &ListNode{Val: 1}
  2. node2 := &ListNode{Val: 2}
  3. node3 := &ListNode{Val: 3}
  4. head.Next = node2
  5. node2.Next = node3
  6. node := head
  7. for {
  8.     if node == nil {
  9.         break
  10.     } else {
  11.         fmt.Println(node.Val)
  12.         node = node.Next
  13.     }
  14. }
复制代码
2. 二叉树

以下是二叉树的结构体:
  1. type TreeNode struct {
  2.     Val   int
  3.     Left  *TreeNode
  4.     Right *TreeNode
  5. }
复制代码
接下来创建一个二叉树,并用前序遍历打印二叉树节点:
  1. func preorderTraversal(root *TreeNode) {
  2.     if root == nil {
  3.         return
  4.     }
  5.     fmt.Println(root.Val)
  6.     if root.Left != nil {
  7.         preorderTraversal(root.Left)
  8.     }
  9.     if root.Right != nil {
  10.         preorderTraversal(root.Right)
  11.     }
  12. }
  13. root := &TreeNode{Val: 1}
  14. root.Left = &TreeNode{Val: 2}
  15. root.Right = &TreeNode{Val: 3}
  16. root.Left.Left = &TreeNode{Val: 4}
  17. root.Left.Right = &TreeNode{Val: 5}
  18. preorderTraversal(root)
复制代码
4、结构体标签

结构体标签是附加在结构体字段后的元数据字符串,可以用于 json 序列化和反序列化、Web 框架表单数据绑定、数据库 ORM 映射等。
下面介绍一下 json 标签的使用。
json 标签

json 标签用于 JSON 的序列化和反序列化,有以下几个功能:

  • 字段映射:json:"field_name" 指定 JSON 字段名,如果不设置,默认为 struct 的字段名
  • 忽略字段:json:"-" 表示该字段不参与序列化
  • 忽略空值:json:"omitempty" 表示如果字段值为零值时,则不参与序列化
  • 类型转换:json:"field_name,string", 表示将数值转换为字符串类型
下面是一个结构体示例:
  1. type Person struct {
  2.     Name        string `json:"name"`
  3.     Age         int    `json:"age,omitempty,string"`
  4.     Gender      string `json:""`
  5.     Address     string `json:"address"`
  6.     NoJsonField string `json:"-"`
  7. }
复制代码
在上面的结构体中,分别对字段实现了下面的操作:

  • 将 Name 字段映射为 json 里的 name 字段
  • Age 字段映射为 age 字段,如果 Age 字段值为零值,则不参与序列化,如果 Age 字段值不为零值,则将 Age 字段值转换为字符串类型
  • Gender 字段映射到 json,但是不改变字段名
  • Address 字段映射为 address 字段
  • NoJsonField 字段不参与序列化
对于这些操作,我们使用下面的代码进行测试,记住,要先引入 json 模块:
  1. import (
  2.     "encoding/json"
  3. )
复制代码
然后进行操作:
  1. person := Person{
  2.     Name:        "Hunter",
  3.     Age:         18,
  4.     Gender:      "Male",
  5.     Address:     "Beijing",
  6.     NoJsonField: "NoJsonValue",
  7. }
  8. _person, err := json.Marshal(person)
  9. if err != nil {
  10.     fmt.Println("JSON 编码错误:", err)
  11. } else {
  12.     fmt.Println(string(_person))
  13. }
  14. // 测试 omitempty,为零值时忽略
  15. person.Age = 0
  16. _person, err = json.Marshal(person)
  17. if err != nil {
  18.     fmt.Println("JSON 编码错误:", err)
  19. } else {
  20.     fmt.Println(string(_person))
  21. }
复制代码
分别打印出两条 json 数据:
  1. {"name":"Hunter","age":"18","Gender":"Male","address":"Beijing"}
  2. {"name":"Hunter","Gender":"Male","address":"Beijing"}
复制代码
输出的结果可以印证前面我们对字段进行的定义逻辑。
除了 json 标签,还有 form 标签用于表单数据绑定,gorm 标签用于数据库映射,validate 标签用于数据验证等,后面有用到的时候再做介绍。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册