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

一、结构体元素

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

二、结构体初步认识

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

1、从存储类型来看

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

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

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

// 声明结构体

type employee struct {

name,address string  // 姓名、住址

age int          // 年龄

height,weight float64 // 身高、体重

}

2、从内存来看

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

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,所以打印出该结果。其实说白了这就是结构体成员的缺省值问题,具体如下图:

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)

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

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

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的成员赋值

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

可以按剥洋葱的思维来理解,若最外层有此成员名(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"}

此时就会抛出如下异常:

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

附件:http://down.51cto.com/data/2365875

本文转自qingkechina 51CTO博客,原文链接:http://blog.51cto.com/qingkechina/1671463,如需转载请自行联系原作者

【Go语言】【12】GO语言的结构体相关推荐

  1. C语言 匿名联合体和匿名结构体

    C语言 匿名联合体和匿名结构体 匿名联合体和匿名结构体顾名思义,就是没有名字的联合体和结构体,没有名字哪怎么用?拿来用? 在嵌入式数据通信里面,大部分都是使用联合体,将有实际意义的结构体和字节数组互相 ...

  2. C语言中函数如何返回结构体?

    //#include "stdafx.h"//If the vc++6.0, with this line. #include "stdio.h" #inclu ...

  3. C语言学生信息管理系统(结构体数组,文件)

    C语言学生信息管理系统(结构体数组,文件) 这是初学时写的一个程序,比较菜,不喜勿喷.在一个结构体里定义结构体内所有的信息(如果信息也需要分类则可以再定义一个结构体并在当前结构体内声明,我的这个代码在 ...

  4. Nwafu-Oj-1444 Problem l C语言实习题七——2.结构体数组的定义与引用

    问题 : C语言实习题七--2.结构体数组的定义与引用 时间限制: 1 Sec  内存限制: 128 MB 提交: 4459  解决: 2011 [提交][状态][讨论版] 题目描述 定义一个职工结构 ...

  5. c语言用数组直接填充结构体,C语言第11题:结构体数组的定义与使用 + 结构体数组排序...

    C语言第11题:结构体数组的定义与使用 + 结构体数组排序 C语言第11题:结构体数组的定义与使用 + 结构体数组排序 注意: 一下赋值是不能使用的 但是在结构体中是可以直接进行赋值操作的 st[1] ...

  6. C语言基础12——自定义类型。结构体、位段、枚举、联合体。通讯录

    目录 结构体 结构体的声明 结构体自引用 结构体变量的定义.初始化以及访问 结构体内存对齐 结构体传参 位段 枚举 枚举是什么? 枚举的声明 枚举的优点 枚举类型的大小 联合体 联合体类型的定义 联合 ...

  7. 【头歌C语言程序与设计】结构体

    目录 写在前面 正文 第1关:结构体变量的初始化和引用 第2关:结构体排序 第3关:结构体存储数据 第4关:结构体存储学生信息 写在最后 写在前面 本文代码是我自己所作,本人水平有限,可能部分代码看着 ...

  8. C语言的sizeof运算符计算结构体大小

    C语言的sizeof运算符运算规则 sizeof运算符 **sizeof 是一个运算符,不是函数(方法).** 例子: 当想打印一个变量的存储区域大小时,可以直接写 int a = 5; printf ...

  9. 【RTOS训练营】课程学习方法和C语言知识(指针、结构体、函数指针、链表)和学员问题

    一.课程学习方法 因为有些学员是刚进群,所以这里再把学习方法讲一下. 1. 预习 我们会在每一节晚课之后会通知要预习的章节,学员需要按如下操作观看相关视频. 1.1 打开百问网官网 ​1.2 点击首页 ...

  10. Go 语言快速入门指南:结构体

    Go语言中没有"类"的概念,也不支持"类"的继承等面向对象的概念. Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. 1. 类型别名和自 ...

最新文章

  1. Three Integers CodeForces - 1311D(思维+暴力)
  2. 15、java中的集合(2)
  3. 路由代码WebApi设置namespace路由参数
  4. 【数据库原理实验(openGauss)】视图
  5. CRCNN PCNN
  6. 怎么在计算机中添加用户账户,使用net user命令在win7电脑中添加账户的步骤
  7. JAVA计算机毕业设计大学生旅游拼团网站Mybatis+源码+数据库+lw文档+系统+调试部署
  8. 山东法律学校97级二班计算机班,关于表彰全国三好学生、全国优秀学生干部和全国先进班集体及其标兵的决定...
  9. U盘格式化后容量变小问题修复方案
  10. 分享个PDF文件签名盖章 DEMO
  11. xxx(telnet, netstat): command not found
  12. AlphaGo对战李世石谁能赢?两万字长文深挖围棋AI技术(一)
  13. Spring中的 @Lazy注解简析
  14. 尚德机构营收同比大涨22.9%,高增长可持续吗?
  15. 使用update!导致的更新时候的错误信息不显示 ruby on rails
  16. 模电——运放输入/输出接小电阻
  17. pv=nrt_中学物理之pV=nRT应用总结篇
  18. 【计算机网络】知识点合集
  19. 3.3V过压保护电路
  20. 一、深度学习笔记(一)

热门文章

  1. gitlab 无法git clone 的一个小点
  2. android多渠道自动打包工具,Android多渠道打包工具
  3. mysql 包含非数字_mysql 正则表达式查询含有非数字和字符的记录
  4. python程序设计祁瑞华答案_【单选题】有六个元素 6 , 5 , 4 , 3 , 2 , 1 的顺序进栈,问下列哪一个不是合法的出栈序列? (2.0分)...
  5. 简述使用混合传递参数时的基本原则_JUnit 5参数化方法测试(一)
  6. 【SRIO】5、Xilinx RapidIO核例子工程源码分析
  7. 【 MATLAB 】离散傅里叶级数(DFS)与DFT、DTFT及 z变换之间的关系
  8. Java基础-锁机制
  9. [深入理解文件系统之十二] ext3文件系统的挂载选项和journal
  10. php取得客户端信息类