本文首发于公众号: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. 【SpringCloud】Ribbon负载均衡调用

    Ribbon负载均衡调用 概述 是什么 Spring Cloud Ribbon是基于Netlix Ribbon实现的一套客户端负载均衡的工具. 简单的说,Ribbon是Netflix发布的开源项目, ...

  2. 【数据结构与算法】不同路径 III:使用哈密尔顿路径算法实现

    [数据结构与算法]不同路径 III:使用哈密尔顿路径算法实现 Java 不同路径 III https://leetcode-cn.com/problems/unique-paths-iii/ 解题思路 ...

  3. PG的子查询:insert 没有就插入记录,update有则更新记录

    insert into t --进行插入 values(1,'name') ON CONFLICT(id) --如果id这个键存在 do update set --更新以下字段 name=EXCLUD ...

  4. zk基础—5.Curator的使用与剖析

    大纲 1.基于Curator进行基本的zk数据操作 2.基于Curator实现集群元数据管理 3.基于Curator实现HA主备自动切换 4.基于Curator实现Leader选举 5.基于Curat ...

  5. Python 潮流周刊#97:CUDA 终于原生支持 Python 了!(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  6. OAuth2.0 学习

  7. 聊聊SpringAI流式输出的底层实现?

    在 Spring AI 中,流式输出(Streaming Output)是一种逐步返回 AI 模型生成结果的技术,允许服务器将响应内容分批次实时传输给客户端,而不是等待全部内容生成完毕后再一次性返回. ...

  8. mysql——修改mysql提示符

    参数 描述 \D 完整日期 \d 当前数据库 \h 服务器名称 \u 当前用户 连接客户端时通过参数指定 mysql -uroot -p密码 --prompt=提示符 mysql -h 192.168 ...

  9. Axure RP仿网易游戏装备饰品APP平台保真交互原型rp源文件

    Axure RP仿网易游戏装备饰品APP平台保真交互原型rp源文件包含以下几个模块: 1.登录和完善信息:绑定steam.获取交易链接.公开设置 2.首页部分:热门关注.数据.热门关注.数据榜.特殊磨 ...

  10. 遇到的问题之“动态数据源报错-recyle error java.lang.InterruptedException”

    Druid出现DruidDataSource - recyle error - recyle error java.lang.InterruptedException: null异常排查与解决 一.线 ...