【go从入门到精通】初识struct结构体

作者简介:


        高科,先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢你的关注)

-------------------------------------------------------------------------------------------------------------------------------

          在Go语言中,没有类的概念,但可以使用struct来定义自定义类型。struct是一种可以包含多个不同类型字段的复合数据类型。可以将它看作是一个数据结构,其中每个字段都有自己的类型和值。

        本文相当于go的数据类型的一部分,在分享struct之前我有必要解释下类型别名和自定义类型的区别:       

类型别名和自定义类型

自定义类型

在Go语言中有一些基本的数据类型,如string、整型、浮点型、布尔等数据类型,Go语言中可以使用type关键字来定义自定义类型。

自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义。例如:

type RANKTYPE int32const (RANKTYPE_GLOBAL_DECORATE        RANKTYPE = 0  //全服装扮排名RANKTYPE_PRIVANCE_DECORATE      RANKTYPE = 1  //省级装扮排名RANKTYPE_FRIEND_DECORATE        RANKTYPE = 2  //好友的装扮排名RANKTYPE_SEASON_SCORE           RANKTYPE = 3  //赛季积分排行榜RANKTYPE_LOCAL_SCORE            RANKTYPE = 4  //本地积分排行RANKTYPE_BIGSEASON_SCORE        RANKTYPE = 5  //赛季积分世界排行榜RANKTYPE_ACTIVITY_SCORE         RANKTYPE = 6  //活动积分排行RANKTYPE_CROSSSEASON_SCORE      RANKTYPE = 7  //跨服美食积分排行  暂时不用,RANKTYPE_SCENCEPROCESS_SCORE    RANKTYPE = 8  //场景进度跨服排行RANKTYPE_DECORATE_SCORE         RANKTYPE = 9  //场景进度跨服排行RANKTYPE_HANDBOOK_SCORE         RANKTYPE = 10 //场景图鉴跨服排行RANKTYPE_COSTUMDESIGNVOTE_SCORE RANKTYPE = 11 //装扮设计投票排行RANKTYPE_PANDFISH_SCORE         RANKTYPE = 12 //钓鱼 池塘鱼的排行记录RANKTYPE_SCTREAMFISH_SCORE      RANKTYPE = 13 //钓鱼 溪流鱼的排行记录RANKTYPE_MARINEFISH_SCORE       RANKTYPE = 14 // 钓鱼 海洋鱼的排行记录RANKTYPE_SCOREFIISHING_SCORE    RANKTYPE = 15 //钓鱼积分的排行记录
)

通过type关键字的定义,RANKTYPE就是一种新的类型,它具有int的特性。

类型别名

类型别名是Go1.9版本添加的新功能。

类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。就像一个孩子小时候有小名、乳名,上学后用学名,英语老师又会给他起英文名,但这些名字都指的是他本人。

    type TypeAlias = Type 

我们之前见过的rune和byte就是类型别名,他们的定义如下:

    type byte = uint8type rune = int32

类型定义和类型别名的区别

类型别名与类型定义表面上看只有一个等号的差异,我们通过下面的这段代码来理解它们之间的区别。

package mainimport "fmt"
//类型定义
type NewInt int//类型别名
type MyInt = intfunc main() {var a NewIntvar b MyIntfmt.Printf("type of a:%T\n", a) fmt.Printf("type of b:%T\n", b)
} 

输出:

结果显示a的类型是main.NewInt,表示main包下定义的NewInt类型。b的类型是int。MyInt类型只会在代码中存在,编译完成时并不会有MyInt类型。

struct结构体

结构体的定义

使用type和struct关键字来定义结构体,具体代码格式如下:

    type 类型名 struct {字段名 字段类型字段名 字段类型…} 

其中:

    1.类型名:标识自定义结构体的名称,在同一个包内不能重复。2.字段名:表示结构体字段名。结构体中的字段名必须唯一。3.字段类型:表示结构体字段的具体类型。 

举个例子,我们定义一个游戏玩家的Player结构体,代码如下:

    type Player struct {playerid     stringname         stringlevel          intexp            intlogintime     int64registertime int64coin         int32gem          int32} 

我们可以把具有相同数据类型的(比如name和playerid)的所有键都在一行上分组和定义:

    type Player struct {playerid,name    stringlevel ,exp         int logintime,registertime     int64coin ,gem        int32} 

这样我们就拥有了一个Player的自定义类型,它有playerid,name等字段。

结构体的tags

结构体的tags是附加到字段中的元数据的小片段,为struct使用该结构的其他 Go 代码提供指令。

例如:这里是名为的自定义类型,Employee可以注释为

type Employee struct {FirstName string `json: "first_name"` LastName  string `json: "last_name"`EmployeeID string `json: "employee_id"`Salary     float64 `json: "salary"`
}

然后,Go 代码能够检查这些结构并提取分配给它请求的特定键的值。如果没有其他代码检查结构标记,则结构标记不会影响代码的操作。

如果我们正在读取YAMLJSON文件,那么我们可以注释struct这样的内容

type Employee struct {FirstName   string  `yaml: "first_name"` LastName    string  `yaml: "last_name"`EmployeeID  string  `yaml: "employee_id"`Salary      float64 `yaml: "salary"`
}
type Manager struct {ManagerFirstName   string  `json: "manager_first_name"` ManagerLastName    string  `json: "manager_last_name"`ManagerEmployeeID  string  `json: "manager_employee_id"`ManagerSalary      float64 `json: "manager_salary"`
}

下面的代码读取文件YAML并将文件中的值分配YAML给变量

var mgr Manager
f, err := os.Open("manager_list.json")if err != nil {log.Fatalf("os.Open() failed with '%s'\n", err)}defer func(f *os.File) {err := f.Close()if err != nil {
}}(f)
mrgObj := yaml.NewDecoder(f)err = mrgObj.Decode(&mgr)if err != nil {log.Fatalf("dec.Decode() failed with '%s'\n", err)}
fmt.Println("%s %s employ_id is %s", mgr.FirstName, mgr.LastName, mgr.EmployeeID)

标准库中的JSON 编码器使用结构标记作为注释,向编码器指示您希望如何命名JSON输出中的字段。这些JSON编码解码机制可以在encoding/json 包中找到。

现在假设您有一个空的 JSON 字段,您想要消除它,那么您可以使用它omitempty,如果JSON对象没有该键的值,则不会填充和跳过它

type Manager struct {ManagerFirstName   string  `json: "manager_first_name"` ManagerLastName    string  `json: "manager_last_name"`ManagerEmployeeID  string  `json: "manager_employee_id"`ManagerSalary      float64 `json: "manager_salary,omitempty"`
}

如果你想忽略某些字段,那么你可以使用-in tags,它将被忽略

type Manager struct {ManagerFirstName   string  `json: "manager_first_name"` ManagerLastName    string  `json: "manager_last_name"`ManagerEmployeeID  string  `json: "manager_employee_id"`ManagerSalary      float64 `json: "-"`
}

如果您想更深入地访问,tags那么您可以使用允许运行时反射的反射包

使用它tag可以让您更轻松地导航存储数据及其表示形式。您可以使用go-playground/validator,它提供了更多有关tags.有些能力就像

  • 字段之间的比较
  • 领域之间的调节
  • 管理字段之间的依赖关系等等……

例如:下面的示例展示了如何使用go-playground/validator来验证字段,而无需编写任何额外的代码。

type Manager struct {ManagerFirstName   string  `json:"manager_first_name" validate:"required"` ManagerLastName    string  `json:"manager_last_name" validate:"required_if=ManagerFirstName"`ManagerEmployeeID  string  `json:"manager_employee_id" validate:"required, gte=1000,lt=10000"`ManagerSalary      float64 `json: "manager_salary,omitempty"`
}

在上面的例子中我能够validate遵循

  • ManagerFirstNamerequired字段
  • ManagerLastNameisrequired_if字段ManagerFirstName已提供
  • ManagerEmployeeIDrequired字段并且不能小于1000

因此,我们可以使用go-playground/validator,而不是为某些基本和条件验证编写数据验证代码,因为它们具有相同的内置逻辑,完全基于tags

只有当结构体实例化时,才会真正地分配
 

结构体实例化

只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。

结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型。

    var 结构体实例 结构体类型 

基本实例化

我们通过var p1 Player的方式来实例化一个Player结构体,并通过.操作来访问或者修改其成员变量

package mainimport ("fmt"  
)
type Player struct {Playerid     string     `json: "playerid"` Name         string     `json: "name"` Level          int  `json: "level"` Exp            int  `json: "exp"` Logintime     int64 `json: "logintime"` Registertime int64  `json: "registertime"` Coin         int32  `json: "coin"` Gem          int32  `json: "gem"` 
}  func main() {var p1 Playerp1.Playerid = "12222222"p1.Name = "高科"p1.Level = 100fmt.Printf("p1=%v\n", p1)  //p1={12222222 高科 100 0 0 0 0 0}fmt.Printf("p1=%#v\n", p1) //p1=main.Player{Playerid:"12222222", Name:"高科", Level:100, Exp:0, Logintime:0, Registertime:0, Coin:0, Gem:0}
} 

或者你可以直接在实例化的同时进行初始化操作,所以下面的初始化方式都可以:

var p1 = Player{playerid:"12222222",Name:"高科",Level: 100, Exp:20, Logintime: 1711296000, Registertime:1701296000, Coin:100000, Gem:999999}

    p2 := Player{playerid:"12222223",Name:"高科2",Level: 100, Exp:20, Logintime: 1711296000, Registertime:1701296000, Coin:100000, Gem:999999}

匿名结构体

在定义一些临时数据结构等场景下还可以使用匿名结构体。

package mainimport ("fmt"  
)
func main() {var p1  struct{playerid     string     `json: "playerid"` Name         string     `json: "name"` Level          int  `json: "level"` Exp            int  `json: "exp"` Logintime     int64 `json: "logintime"` Registertime int64  `json: "registertime"` Coin         int32  `json: "coin"` Gem          int32  `json: "gem"` }  p1.playerid = "12222222"p1.Name = "高科"p1.Level = 100fmt.Printf("p1=%v\n", p1)  //p1={12222222 高科 100 0 0 0 0 0}fmt.Printf("p1=%#v\n", p1) //p1=main.Player{Playerid:"12222222", Name:"高科", Level:100, Exp:0, Logintime:0, Registertime:0, Coin:0, Gem:0}
} 

创建指针类型结构体

我们还可以通过使用new关键字或者&对结构体进行实例化,得到的是结构体的地址。 格式如下:

var 变量名 new(struct类型)

package mainimport ("fmt"  
)
type Player struct {playerid     string     `json: "playerid"` Name         string     `json: "name"` Level          int  `json: "level"` Exp            int  `json: "exp"` Logintime     int64 `json: "logintime"` Registertime int64  `json: "registertime"` Coin         int32  `json: "coin"` Gem          int32  `json: "gem"` 
}  func main() {var p1 = new(Player) var p2 = &Player{} fmt.Printf("p1=%v ,p2=%v \n", p1,p2)  //p1=&{  0 0 0 0 0 0} fmt.Printf("p1=%#v ,p2=%#v \n", p1,p2) //p1=&main.Player{playerid:"", Name:"", Level:0, Exp:0, Logintime:0, Registertime:0, Coin:0, Gem:0} 
} 

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

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

相关文章

虚拟网络设备性能优化

在现代网络架构中,虚拟网络设备扮演着越来越重要的角色🌐,特别是在云计算☁️和容器化技术📦广泛应用的背景下。虚拟网络设备如虚拟以太网设备(veth)、虚拟交换机(vSwitch)、和虚拟路…

适用于 Mac 的 10 大数据恢复工具,具有优点、缺点

数据丢失很常见,并且可能由于许多不同的原因而发生。这种情况在我和我们团队的其他成员身上发生过很多次,即使我们格外小心我们的个人存储设备。 幸运的是,数据恢复软件在大多数情况下都可以工作。但是,由于数据丢失场景彼此之间…

【CKA模拟题】边车容器Shared-Volume的具体用法

Useful Resources: Persistent Volumes Claim , Pod to Use a PV 题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetes An existing nginx pod, my-pod-cka and Persistent Volume Claim…

macOS制作C/C++ app

C/C制作macOS .app 一、 .app APP其实是一个文件夹结构,只不过mac的界面中让它看起来像一个单独的文件。 在shell终端或者右键查看包结构即可看到APP的目录结构。 通常的app目录结构如下: _CodeSignature, CodeResources 一般为Mac APP Store上架程序…

【aws】在DBeaver上用终端节点连接Redshift

碎碎念 最近想要尝试redshift的一个叫做重新定位的功能,重新定位触发之后会停止当前的集群,转而在同一个区域的另一个可用区中启动一个一样的集群,这个过程视情况会花上10到60分钟不等。 但是目前项目中连接到redshift用的是私有ip&#xf…

保研线性代数复习4

一.范数(Norms) 1.什么是范数? 范数是一个向量空间V的函数,每一个属于向量空间V的向量x都匹配了一个实数(它的长度): 2.范数的性质? 齐次性: 正定性: 三…

大创项目推荐 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满分5分) …

【Python】基础(专版提升1)

Python基础 1. 导学1.1 学习理念1.1.1 弱语法,重本质1.1.2 是技术,更艺术 1.2 学习方法1.2.1 当天知识必须理解 2. Python 简介2.1 计算机基础结构2.1.1 硬件2.1.2 软件 2.2 基础知识2.2.1 Python介绍2.2.1.1定义2.2.1.2优势2.2.1.3从业岗位 2.2.2 Pytho…

openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警

文章目录 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 Plan Hint的结果会体现在计划的变化上,可以通过explain来查看变化。 …

负荷预测 | Matlab基于TCN-GRU-Attention单输入单输出时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于TCN-GRU-Attention单输入单输出时间序列多步预测; 2.单变量时间序列数据集,采用前12个时刻预测未来96个时刻的数据; 3.excel数据方便替换,运行环境matlab20…

[法规规划|数据概念]数据要素市场三月速递

“ 代表关注,市场活跃,发展迅速” 01—听听两会代表怎么说 在2024年的全国两会期间,数据要素作为新型的生产要素受到广泛关注,众多代表围绕数据要素市场化、立法、安全监管、人才培养及基础设施建设等方面,积极建言献策…

P8602 [蓝桥杯 2013 省 A] 大臣的旅费【树的直径】

P8602 [蓝桥杯 2013 省 A] 大臣的旅费 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<iostream> #include <algorithm> #include <vector> using namespace std; #define int long long const int N5e5100; int n; int res0; typedef pair<int,…

植物大战僵尸Python版,附带源码注解

目录 一、实现功能 二、安装环境要求 三、如何开始游戏 四、怎么玩 五、演示 六、部分源码注释 6.1main.py 6.2map.py 6.3Menubar.py 七、自定义 7.1plant.json 7.2zombie.json 一、实现功能 实施植物&#xff1a;向日葵、豌豆射手、壁桃、雪豆射手、樱桃炸弹、三…

【前端】学习路线

1、基础 1.1 HTML 菜鸟教程-主页&#xff1a;https://www.runoob.com/ 可以学习&#xff1a;HTML、CSS、Bootstrap等 1.2 CSS 《通用 CSS 笔记、建议与指导》 1.3 JavaScript 1&#xff09;入门&#xff1a;JavaScript 的基本语法 2&#xff09;进阶&#xff1a;现代 …

蓝桥杯中的DFS算法

前言 和上一篇文章一样&#xff0c;这篇文章是介绍蓝桥杯中的第二种暴力算法就是DFS算法&#xff0c;在蓝桥杯中非常常用。 简单介绍 DFS算法中文名就是深度优先算法&#xff0c;在这里就不详细介绍这个算法了&#xff0c;可以自行搜索&#xff0c;网上有很多&#xff0c;或…

Http客户端Feign

RestTemplate存在的问题 这是一段使用RestTemplate来发起远程调用的代码&#xff0c;存在以下问题 1&#xff0c;代码可读性差&#xff0c;编程体验不统一&#xff08;其实还好&#xff09; 2&#xff0c;复杂的url难以维护&#xff0c;修改起来十分麻烦 3&#xff0c;总结…

thinkphp5关联预载入with指定字段属性查询

一、thinkphp5.0 如果要指定属性查询&#xff0c;可以使用&#xff1a; $list User::field(id,name)->with([profile>function($query){$query->field(email,phone);}])->select([1,2,3]); foreach($list as $user){// 获取用户关联的profile模型数据dump($user…

MSTP/RSTP的保护功能

目录 原理概述 实验目的 实验内容 实验拓扑 1.配置RSTP/MSTP 2.配置BPDU保护 3.配置根保护 4.配置环路保护 5.配置TC-BPDU保护 原理概述 在RSTP或MSTP交换网络中&#xff0c;为了防止恶意攻击或临时环路的产生&#xff0c;可配置保护功能来增强网络的健壮性和安全性。…

openstack中windows虚拟机时间显示异常问题处理

文章目录 一、问题描述二、元数据信息总结 一、问题描述 openstack创建出windows虚拟机的时候&#xff0c;发现时间和当前时间相差8小时&#xff0c;用起来很难受。 参考&#xff1a;https://www.cnblogs.com/hraa0101/p/11365238.html 二、元数据信息 通过设置镜像的元数据…

pytest教程-24-多重断言插件-pytest-assume

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest指定用例执行顺序插件pytest-ordering,本小节我们讲解一下pytest多重断言插件-pytest-assume。 在自动化测试过程中&#xff0c;我们执行完用例之后&#xff0c;需要验证脚本执行的结果…