本文首发于公众号:Hunter后端

原文链接:Golang基础笔记五之结构体

本篇笔记介绍 Golang 中的结构体。

在 Go 中,结构体是一种用户自定义的数据类型,可以将不同类型的数据组合在一起。

以下是本篇笔记目录:

  1. 结构体的定义和使用
  2. 嵌套结构体
  3. 创建结构体递归结构
  4. 结构体标签

1、结构体的定义和使用

结构体定义的基本语法如下:

type 结构体名称 struct{
    field1 type
    field2 type
}

我们可以先创建一个 struct:

type Person struct {
    Name string
    Age  int
}

下面介绍几种方式来实例化结构体:

1. 使用结构体字面量初始化

使用结构体字面量初始化结构体变量,在创建结构体变量时,将字段值直接赋给结构体的字段。

其语法如下:

person := Person{Name: "Alice", Age: 30}
fmt.Println(person)

在这里,如果有字段没有赋值,那么这个字段的值就是该类型的零值。

2. 按字段顺序初始化

我们可以在初始化的时候不指定字段,那么它会按照结构体中的字段顺序进行赋值:

person := Person{"Alice", 30}
fmt.Println(person)

但是这个操作有个问题,就是结构体中的全部字段都需要赋值。

3. 使用 new 函数创建结构体指针

可以使用 new() 函数创建一个结构体,但是注意,其返回值是对应结构体的指针:

var person *Person = new(Person)
person.Age = 1
person.Name = "Hunter"

2、嵌套结构体

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

1. 匿名嵌套

在嵌套的时候如果直接嵌套不指定字段名,这个就叫匿名嵌套,比如下面的示例:

type Address struct {
    City string
}
type Person struct {
    Name string
    Age  int
    Address
}

这里没有给 Address 指定字段名,所以这个 Address 就是一个匿名字段。

以下是一个初始化的例子:

person := Person{
    Name: "Hunter",
    Age:  18,
    Address: Address{
        City: "Beijing",
    },
}

使用匿名嵌套,我们可以直接访问到嵌套的结构体的字段:

fmt.Println(person.City)

这里 City 是 Addree 结构体的字段,但因为是匿名嵌套,所以可以直接访问到。

当然,也可以通过 Address 结构体进行访问:

fmt.Println(person.Address.City)

2. 具名嵌套

如果嵌套的时候显式指定字段名,就叫具名嵌套,比如:

type Company struct {
    CompanyName string
}
type Person struct {
    Name string
    Age  int
    CompanyInfo Company
}

这里为了以示区分,给 Company 结构体的字段名设为 CompanyInfo,其初始化的方式还是类似的:

person := Person{
    Name: "Hunter",
    Age:  18,
    CompanyInfo: Company{
        CompanyName: "ACompany",
    },
}

而如果要访问到嵌套的结构体的字段,则需要通过 CompanyInfo 进行访问:

fmt.Println(person.CompanyInfo.CompanyName)

3、创建结构体递归结构

我们可以通过结构体嵌套自己来形成递归结构,但是嵌套的类型需要是自身结构体的指针。

下面介绍一下使用结构体来创建链表和二叉树。

1. 链表

链表的结构体如下:

type ListNode struct {
    Val  int
    Next *ListNode
}

接下来创建一个链表,并打印节点内容:

head := &ListNode{Val: 1}
node2 := &ListNode{Val: 2}
node3 := &ListNode{Val: 3}
head.Next = node2
node2.Next = node3
node := head
for {
    if node == nil {
        break
    } else {
        fmt.Println(node.Val)
        node = node.Next
    }
}

2. 二叉树

以下是二叉树的结构体:

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

接下来创建一个二叉树,并用前序遍历打印二叉树节点:

func preorderTraversal(root *TreeNode) {
    if root == nil {
        return
    }
    fmt.Println(root.Val)
    if root.Left != nil {
        preorderTraversal(root.Left)
    }
    if root.Right != nil {
        preorderTraversal(root.Right)
    }
}
root := &TreeNode{Val: 1}
root.Left = &TreeNode{Val: 2}
root.Right = &TreeNode{Val: 3}
root.Left.Left = &TreeNode{Val: 4}
root.Left.Right = &TreeNode{Val: 5}
preorderTraversal(root)

4、结构体标签

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

下面介绍一下 json 标签的使用。

json 标签

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

  1. 字段映射:json:"field_name" 指定 JSON 字段名,如果不设置,默认为 struct 的字段名
  2. 忽略字段:json:"-" 表示该字段不参与序列化
  3. 忽略空值:json:"omitempty" 表示如果字段值为零值时,则不参与序列化
  4. 类型转换:json:"field_name,string", 表示将数值转换为字符串类型

下面是一个结构体示例:

type Person struct {
    Name        string `json:"name"`
    Age         int    `json:"age,omitempty,string"`
    Gender      string `json:""`
    Address     string `json:"address"`
    NoJsonField string `json:"-"`
}

在上面的结构体中,分别对字段实现了下面的操作:

  1. 将 Name 字段映射为 json 里的 name 字段
  2. Age 字段映射为 age 字段,如果 Age 字段值为零值,则不参与序列化,如果 Age 字段值不为零值,则将 Age 字段值转换为字符串类型
  3. Gender 字段映射到 json,但是不改变字段名
  4. Address 字段映射为 address 字段
  5. NoJsonField 字段不参与序列化

对于这些操作,我们使用下面的代码进行测试,记住,要先引入 json 模块:

import (
    "encoding/json"
)

然后进行操作:

person := Person{
    Name:        "Hunter",
    Age:         18,
    Gender:      "Male",
    Address:     "Beijing",
    NoJsonField: "NoJsonValue",
} _person, err := json.Marshal(person) if err != nil {
    fmt.Println("JSON 编码错误:", err)
} else {
    fmt.Println(string(_person))
} // 测试 omitempty,为零值时忽略
person.Age = 0
_person, err = json.Marshal(person)
if err != nil {
    fmt.Println("JSON 编码错误:", err)
} else {
    fmt.Println(string(_person))
}

分别打印出两条 json 数据:

{"name":"Hunter","age":"18","Gender":"Male","address":"Beijing"}
{"name":"Hunter","Gender":"Male","address":"Beijing"}

输出的结果可以印证前面我们对字段进行的定义逻辑。

除了 json 标签,还有 form 标签用于表单数据绑定,gorm 标签用于数据库映射,validate 标签用于数据验证等,后面有用到的时候再做介绍。

Golang基础笔记五之结构体的更多相关文章

  1. Golang基础(4):Go结构体

    当我们要表示同一种数据类型时候,可以用到数组,切片和字典. 当我们要表示不同的数据类型呢?这时候就要用到结构体了 一:定义struct 关键字 type 和 struct 来定义结构体 type st ...

  2. Golang面向对象编程-struct(结构体)

    Golang面向对象编程-struct(结构体) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是面向对象编程 面向对象编程(Object Oriented Program ...

  3. Golang Json文件解析为结构体工具-json2go

    代码地址如下:http://www.demodashi.com/demo/14946.html 概述 json2go是一个基于Golang开发的轻量json文件解析.转换命令行工具,目前支持转换输出到 ...

  4. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  5. C#学习笔记05--枚举/结构体

    一.枚举   当变量的取值范围是固定的几个时, 就可以使用枚举类型, 这样会更加简洁方便   1.1.定义: 访问修饰符 enum 枚举类型名 { 成员1, 成员2, 成员3, ... } publi ...

  6. matlab学习笔记12_3串联结构体,按属性创建含有元胞数组的结构体,filenames,isfield,isstruct,orderfields

    一起来学matlab-matlab学习笔记12 12_3 结构体 串联结构体,按属性创建含有元胞数组的结构体,filenames,isfield,isstruct,orderfields 觉得有用的话 ...

  7. Golang通过反射拼接一个结构体所有字段

    golang通过反射拼接一个结构体所有字段 需求 将一个结构体所有字段以"|"连接拼接成字符串 golang 不同类型拼接成string使用Sprintf比较麻烦,如果一个结构体有 ...

  8. GO语言系列(五)- 结构体和接口

    结构体(Struct) Go中struct的特点 1. 用来自定义复杂数据结构 2. struct里面可以包含多个字段(属性) 3. struct类型可以定义方法,注意和函数的区分 4. struct ...

  9. Golang基础笔记

    <基础> Go语言中的3个关键字用于标准的错误处理流程: defer,panic,recover. 定义一个名为f 的匿名函数: Go 不支持继承和重载. Go的goroutine概念:使 ...

  10. C#基础知识之类和结构体

    虽然项目中一直在使用类.结构体等类型,仔细琢磨,还真无法系统的说出个所以然.记录一下类.结构体.类和结构体区别 一.类 对于类,大家都特别熟悉.简单的介绍一下类的结构,然后记录一下Class需要注意的 ...

随机推荐

  1. 【Java】Math类的基本操作

    Math类 Math 类是数学操作类,提供了一系列的数学操作方法,包括求绝对值.三角函数等,在 Math 类中提供的一切方法都是静态方法(类方法),所以直接由类名称调用即可. Math类的基本操作: ...

  2. AI 应用思考

    之前看到过一个理论,创新技术的三个阶段:新技术创造-精英服务-平民化 技术扩散的三阶段理论模型 1. 创新垄断期(精英创造阶段)技术革命初期,创新活动高度依赖知识密集型投入.AI发展呈现"分 ...

  3. 【Java】Java提取${}占位符并组装对应值

    目录 Java提取${}占位符并组装对应值 零.起因 壹.想法 贰.实现 叁.总结 肆.参考文档 Java提取${}占位符并组装对应值 实现了一个${}装配工~ 零.起因 最近写个JavaWeb项目, ...

  4. .NET 阻止关机机制以及关机前执行业务

    本文主要介绍Windows在关闭时,如何正确.可靠的阻止系统关机以及关机前执行相应业务.因有一些场景需要在关机/重启前执行业务逻辑,确保下次开机时数据的一致性以及可靠性. 以下是实现这一需求的几种方法 ...

  5. Launchpool名词解释

    # 一.什么是Launchpool Launchpool是一种加密货币领域的创新机制,通常由交易所或DeFi平台提供,允许用户通过质押(staking)或锁定特定代币来获得新项目的代币奖励. ## L ...

  6. VSCode输出框中文乱码问题

    vscode输出中文的时候,总是出现乱码.找了一个一劳永逸解决问题的方法,转载的,原教程地址:https://blog.csdn.net/a19990412/article/details/90270 ...

  7. vue3在构建时,使用魔法糖语法时defineProps和defineEmits的注意事项

    在 Vue 3.2+ 版本中,可以使用 <script setup> 替代传统的 script标签来编写组件,它提供了更简洁的语法来编写 Composition API 代码. 在 < ...

  8. 1779. 找到最近的有相同 X 或 Y 坐标的点

    1779. 找到最近的有相同 X 或 Y 坐标的点 class Solution { public int nearestValidPoint(int x, int y, int[][] points ...

  9. @EnableAspectJAutoProxy

    开启动态代理配置 官方文档 通过xml配置 <aop:aspectj-autoproxy proxy-target-class="true"/> 通过注解配置 @Ena ...

  10. 容器化 MCP Server!

    大家好!我是韩老师. 本文是 MCP 系列文章的第五篇,之前的四篇是: Code Runner MCP Server,来了! 从零开始开发一个 MCP Server! 一键安装 MCP Server! ...