本文首发于公众号: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. [源码系列:手写spring] IOC第十节:bean的初始化和销毁方法

    内容介绍 在Spring框架中,你可以使用以下几种方法定义bean的初始化和销毁: 使用注解方式: @PostConstruct:在bean的方法上添加@PostConstruct注解,该方法将在be ...

  2. Code First 初始化数据时发生异常

    问题重现 用Entity Framework的Code First默认生成的数据库文件被我直接删除了, 然后不管怎么重新编译等等, 运行后总是会报错如下: 解决方案同下 Cannot attach t ...

  3. JBoltAI Function Call技术解析:如何实现AI模型与企业系统的无缝对话

    JBoltAI Function Call技术解析: 如何实现AI模型与企业系统的无缝对话 在企业级AI应用开发中,如何让大模型能力与现有系统高效协同一直是技术难点.JBoltAI框架通过Functi ...

  4. DeepseekScanner deepseek+python实现代码审计实战

    一.功能概述 DeepseekScanner实现了扫描源代码项目中的所有代码文件发送给deepseek进行安全审计的功能.具体细节包括扫描所有子目录中的代码文件,然后依次将代码文件切片发送到deeps ...

  5. 一些CF上的补题0504

    知识点模块 1.通过三点计算三角形的面积可以这样写 area=fabs(x1*y2-x2*y1+x2*y3-x3*y2+x3*y1-x1*y3)/2; 2.最小公倍数与最大公约数 x×y=gcd(x, ...

  6. 极客时间上新 .NET + AI 体系课

    课程特色 1️⃣ 全网首个.NET+AI体系化课程(没有之一!) 2️⃣ Semantic Kernel + Kernel Memory 核心知识全覆盖 3️⃣ 每课时基于Polyglot Noteb ...

  7. Vue3+Ant-design项目启用ts/typescript

    Ant-design官方文档提供了js和ts两种案例,按照文档给项目install ant-design后写了个组件编译时发现只要加上`<script lang="ts"&g ...

  8. JS 对象(Object)和字符串(String)互转方法、JS遍历对象

    原文:https://www.cnblogs.com/fps2tao/p/8723164.html 1.对象(Object)和字符串(String)互转 利用原生JSON对象,将对象转为字符串 var ...

  9. 通过Linux包管理器提升权限

    免责声明:本文所涉及的技术仅供学习和参考,严禁使用本文内容从事违法行为和未授权行为,如因个人原因造成不良后果,均由使用者本人负责,作者及本博客不承担任何责任. 前言 在Linux系统中,apt和yum ...

  10. Spring基于xml的CRUD

    目录 基于xml的CRUD 代码实现 测试 基于xml的CRUD 源码 使用C3P0连接池 使用dbutils包中的QueryRunner类来对数据库进行操作 代码实现 pom.xml <?xm ...