【Go语言】【12】GO语言的结构体

简介:
原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://qingkechina.blog.51cto.com/5552198/1671463

       当我第一次接触到C语言时,就对结构体投入了极大的兴趣,认为这个东西以后大有作为,后来接触Java、C++,面向对象编程中的对象进入我的视线,经过了这么多年的磨练,回过头来再看结构体依旧是那么亲切;同时从另一个角度上看结构体与面向对象中的成员对象是多么的相像 :)

一、结构体元素

结构体由关键字、结构体类型名称和具体成员构成,如下:

wKiom1WaZv2RbnY3AAC_DN43xqI956.jpg


二、结构体初步认识

下面通过对比数组(复合类型)来了解一下结构体:

1、从存储类型来看

数组只能存储相同的类型:

s := []string{"a", "b", "c", "d", "e"}

结构体可以存储不同的类型

// 声明结构体

type employee struct {

   name,address string  // 姓名、住址

   age int          // 年龄

   height,weight float64 // 身高、体重

}


2、从内存来看

它们都是在内存中占据连续的内存空间,但对于数组来说,每一个元素所占用的内存大小是相同的,而结构体每一个项所占用的内存大小不一定相同

wKioL1WacC7ARF99AAB2IrtGm7Q976.jpg


3、从类型组合角度来看

数组没有组合的用法,例如一个一维数组,一旦数组类型确定就不可以再把另一个一维数组设置为元素值,例如

s := []string{"a", "b", "c", "d", "e"}

s[0] = []string{"f", "g"}

此时运行该程序会出现类似此提示:cannot use []string literal (type []string) as type string in assignment;

结构体支持组合,我们知道一维空间是一条线,二维空间是一个平面,三维空间是一个空间

type line struct {

   x int

}


type plane struct {

   line

   y int

}


type space struct {

   plane

   z int

}

我们很自然地通过组合的方式,把一维扩展到二维,把二维扩展到三维,把三维扩展到四维,依次类推......


4、从操作角度上来看

数组元素的操作是通过下标来完成的:

s := []string{"a", "b", "c", "d", "e"}

for i := 0; i < len(s); i++ {

   fmt.Println(s[i])     // 打印数组中每一个元素,通过s[i]下标的方式来获取

}

而结构体是通过项名来完成的:

t := space{plane{line{3}, 5}, 7}

fmt.Println(t.x, t.y, t.z)   // 通过操作结构体的项名t.x、t.y、t.z来获取


5、从比较角度上来看

数组与结构体类似,若判断两个数组是否相同,需要看数组的存储类型、数组长度、每一个元素是否相等,同样判断两个结构体是否相同,需要看结构体的类型是否相同,然后看项的顺序、项的名称、项的类型等等


三、结构体的初始化

关于数组的初始化可参见《【6】GO语言的数组》,相对数组结构体的初始化有点繁杂,下面一一道来:

1、空结构体

所谓空结构体,即结构体的成员为空,如下:

// 声明空结构体employee

type employee struct {

}


func main(){

   emp := employee{}   // 结构体的初始化,直接使用结构体类型名称后面跟一个大括号

   fmt.Println(emp)

}

其中employee{}就表示初始化一个结构体,然后赋值给emp,运行就会打印出结果{},因为该结构体成员为空;可能有读者想,若结构体有成员,同样这样初始化会有什么结果呢?

type employee struct {

   name, address  string  // 姓名、住址

   age         int    // 年龄

   height, weight  float64 // 身高、体重

}


func main(){

   emp := employee{}   // 这样有什么结果呢?

   fmt.Println(emp)

}

运行一下就会发现,结果是{  0 0 0},因为字符串的缺省值为空串,不会显示出来,而int和float64的缺省值为0,所以打印出该结果。其实说白了这就是结构体成员的缺省值问题,具体如下图:

wKioL1WafAnhdRBGAABTJEO04ow570.jpg


2、结构体的初始化

结构体的成员初始化是通过操作成员对象来完成

func main() {

   emp := employee{}

   fmt.Println(emp)


   emp.name = "黑客eagle"

   emp.age = 38

   fmt.Println(emp)

}

采用变量+"."+成员名=值的形式对结构体进行初始化,例如emp.age=38。这种初始化形式很类似C++、Java,那么是否还有其它形式呢?当然,以前说过GO语言就是人的正常思维语言,只要你能想到,基本上就可以正常执行 :)

emp1 := employee{"keji", "hangzhou", 19, 175, 65}

fmt.Println(emp1)

这种初始化形式看起来更直观。上面的执行结果如下:

wKioL1WafuWiLtDKAABqafzO-4U073.jpg

读者可能还会问,我只想对其中的某几个成员赋值,而上面是对所有成员赋值,该如何办呢?

emp2 := employee{address: "hangzhou", age: 20}

fmt.Println(emp2)

这样只有被指定赋值的成员才能得到真实的值,而未指定赋值的成员则被系统赋予缺省值,这种情况也被称为采用字面值进行初始化


3、嵌套结构体

这个比较好理解,即结构体里面嵌套结构体,我们把“身高”、“体重”定义为一个结构体,而“身高”、“体重”是一个human(结构体)的成员,所以可以采用嵌套结构体:

// 体形

type figure struct {

   height, weight float64

}


type human struct {

   name, address string

   figure

}

即human结构体中包含figure结构体,我们可以采用下面的初始化

man := human{}

fmt.Println(man)

执行结果为{  {0 0}}


结合上面讲的结构体初始化,我们很容易通过字面值对name和address初始化

man.name = "siyu"

man.address = "tianjin"

但是怎么对嵌套的结构体成员height、weight进行初始化呢?用过面向对象编程的人很容易想到,采用如下方式:

func main() {

   man := human{}

   man.name = "siyu"

   man.address = "tianjin"


   man.figure.height = 172.8

   man.figure.weight = 175.3

   fmt.Println(man)

}

即一层层向下找:先找man的成员figure,然后通过figure的成员height对身高进行赋值,这样没有问题,其实GO给我们提供了一种更便捷的赋值方式:

man.height = 172.8

man.weight = 175.3

即直接对其成员赋值,这种方式简单直接,但会引入“成员可见性”的概念


4、结构体成员的可见性

任何语言在代码面前都是苍白的,敏捷有一个思想就是代码胜过文档,费话少说,用代码来解释什么是“结构体成员的可见性”

// 生物会笑、会哭,所以有哭、笑成员

type biology struct {

   cry, laugh string

}


// 人会笑、会哭,所以也有哭、笑成员;但同时人嵌套了生物结构体

type human struct {

   biology

   cry, laugh string

}

下面采用如下方式对结构体初始化

man := human{}

man.cry = "cry"

man.laugh = "laugh"

fmt.Println(man)

那么这里的man.cry,man.laugh是对human的成员赋值呢?还是对biology的成员赋值呢?运行一下结果便可以知道,这里是对human的成员赋值

wKioL1WahjbCH1-XAABJlgjXV78216.jpg

因为内层大括号是空的,为什么这样呢?

可以按剥洋葱的思维来理解,若最外层有此成员名(cry、laugh)则不用再向里面剥了,若最外层没有该成员名,则进一步向里面剥,直到找到为止;

这也就是说,若外层有成员名(cry、laugh),则内层的同名成员是不可见的,若外层没有成员名(cry、laugh),内层的成员才变的可见


5、再谈嵌套结构体的初始化

以上例来说,我们可以采用字面值的形式初始化:

man := human{}

man.cry = "cry"

man.laugh = "laugh"

man.biology.cry = "biology cry"

man.biology.laugh = "biology laugh"

其实还可以采用如下形式:

woman := human{biology: biology{cry: "biology cry", laugh: "biology laugh"}cry: "cry"laugh: "laugh"}

还可以简化为:

woman := human{biology: biology{"biology cry", "biology laugh"}cry: "cry"laugh: "laugh"}

是否还可以简化为?

woman := human{{"biology cry", "biology laugh"}, "cry", "laugh"}

此时就会抛出如下异常:

wKiom1WaiYqAE2bqAACJITQRi6Y131.jpg

你如果够仔细的话,就能发现嵌套结构体就只写了一个结构体类型名,而没有采用value valueType的形式,所以针对这种情况,GO语言认为内部嵌套结构体名称和类型名是同一个

本文出自 “青客” 博客,请务必保留此出处http://qingkechina.blog.51cto.com/5552198/1671463

目录
相关文章
|
8天前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
39 0
|
1天前
|
存储 编译器 Go
Go语言学习12-数据的使用
【5月更文挑战第5天】本篇 Huazie 向大家介绍 Go 语言数据的使用,包含赋值语句、常量与变量、可比性与有序性
32 6
Go语言学习12-数据的使用
|
3天前
|
Java Go
一文带你速通go语言指针
Go语言指针入门指南:简述指针用于提升效率,通过地址操作变量。文章作者sharkChili是Java/CSDN专家,维护Java Guide项目。文中介绍指针声明、取值,展示如何通过指针修改变量值及在函数中的应用。通过实例解析如何使用指针优化函数,以实现对原变量的直接修改。作者还邀请读者加入交流群深入探讨,并鼓励关注其公众号“写代码的SharkChili”。
9 0
|
3天前
|
存储 缓存 Java
来聊聊go语言的hashMap
本文介绍了Go语言中的`map`与Java的不同设计思想。作者`sharkChili`是一名Java和Go开发者,同时也是CSDN博客专家及JavaGuide项目的维护者。文章探讨了Go语言`map`的数据结构,包括`count`、`buckets指针`和`bmap`,解释了键值对的存储方式,如何利用内存对齐优化空间使用,并展示了`map`的初始化、插入键值对以及查找数据的源码过程。此外,作者还分享了如何通过汇编查看`map`操作,并鼓励读者深入研究Go的哈希冲突解决和源码。最后,作者提供了一个交流群,供读者讨论相关话题。
13 0
|
4天前
|
Java Go
Go语言学习11-数据初始化
【5月更文挑战第3天】本篇带大家通过内建函数 new 和 make 了解Go语言的数据初始化过程
17 1
Go语言学习11-数据初始化
|
4天前
|
自然语言处理 安全 Java
速通Go语言编译过程
Go语言编译过程详解:从词法分析(生成token)到句法分析(构建语法树),再到语义分析(类型检查、推断、匹配及函数内联)、生成中间码(SSA)和汇编码。最后,通过链接生成可执行文件。作者sharkchili,CSDN Java博客专家,分享技术细节,邀请读者加入交流群。
22 2
|
4天前
|
Java Linux Go
一文带你速通Go语言基础语法
本文是关于Go语言的入门介绍,作者因其简洁高效的特性对Go语言情有独钟。文章首先概述了Go语言的优势,包括快速上手、并发编程简单、设计简洁且功能强大,以及丰富的标准库。接着,文章通过示例展示了如何编写和运行Go代码,包括声明包、导入包和输出语句。此外,还介绍了Go的语法基础,如变量类型(数字、字符串、布尔和复数)、变量赋值、类型转换和默认值。文章还涉及条件分支(if和switch)和循环结构(for)。最后,简要提到了Go函数的定义和多返回值特性,以及一些常见的Go命令。作者计划在后续文章中进一步探讨Go语言的其他方面。
10 0
|
5天前
|
JavaScript 前端开发 Go
Go语言的入门学习
【4月更文挑战第7天】Go语言,通常称为Golang,是由Google设计并开发的一种编程语言,它于2009年公开发布。Go的设计团队主要包括Robert Griesemer、Rob Pike和Ken Thompson,这三位都是计算机科学和软件工程领域的杰出人物。
14 1
|
6天前
|
Go
|
6天前
|
分布式计算 Java Go
Golang深入浅出之-Go语言中的分布式计算框架Apache Beam
【5月更文挑战第6天】Apache Beam是一个统一的编程模型,适用于批处理和流处理,主要支持Java和Python,但也提供实验性的Go SDK。Go SDK的基本概念包括`PTransform`、`PCollection`和`Pipeline`。在使用中,需注意类型转换、窗口和触发器配置、资源管理和错误处理。尽管Go SDK文档有限,生态系统尚不成熟,且性能可能不高,但它仍为分布式计算提供了可移植的解决方案。通过理解和掌握Beam模型,开发者能编写高效的数据处理程序。
135 1