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

当我第一次接触到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、空结构体

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

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.8man.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语言认为内部嵌套结构体名称和类型名是同一个

时间: 2024-11-08 08:46:38

【Go语言】【12】GO语言的结构体的相关文章

C语言中的系统时间结构体类型

在C语言涉及中经常需要定时触发事件,涉及到获取系统时间,其结构体类型有多种.Unix/Linux系统下有以下几种时间结构: 1.time_t 类型:长整型,一般用来表示从1970-01-01 00:00:00时以来的秒数,精确度:秒:由函数time()获取: 该类型定义在头文件 /usr/include/sys/time.h 中: #define _TIME_T       typedef   long   time_t;             #endif 函数定义:time_t   tim

「C语言」「例题」结构体与共用体

本篇收集<C语言程序设计教程>第九章“结构体与共用体”的所有例题. 1 #include <stdio.h> 2 3 /*输入一个学生的基本信息, 4 包括学号.姓名.性别.年龄.出生日期.三门成绩, 5 输出该学生的基本信息和平均成绩*/ 6 7 struct date 8 { 9 int year;/* 年份 */ 10 int month;/* 月份 */ 11 int day; /* 日期 */ 12 }; 13 14 struct student 15 { 16 char

C语言--&gt;(十四)结构体、宏、编译

知识点: 1.结构体 struct 2.typedef关键字 3.宏的定义 4.宏与函数的区别 5.文件包含和多文件编译 6.条件编译 ===========================结构体 思考:如果现在希望保存一个学生的信息,姓名,身高,年龄,地址,该如何保存 char name[64]; float height; int age; char addr[64]; 1.什么是结构体 struct 结构体指的是一种数据结构,是c语言中复合数据类型的一 种多种不同数据类型的集合 2.结构体

菜鸟学习-C语言函数参数传递详解-结构体与数组

C语言中结构体作为函数参数,有两种方式:传值和传址. 1.传值时结构体参数会被拷贝一份,在函数体内修改结构体参数成员的值实际上是修改调用参数的一个临时拷贝的成员的值,这不会影响到调用参数.在这种情况下,涉及到结构体参数的拷贝,程序空间及时间效率都会受到影响. 例子: typedef struct tagSTUDENT{ char name[20]; int age; }STUDENT; void fun(STUDENT stu) { printf("stu.name=%s,stu.age=%d/

C++ c++与C语言的区别(空结构体)

//区别⑨:空结构体声明(C++版本) #include<iostream> using namespace std; struct A{}; class B{}; void main(){ printf("C++中空结构体内存大小是%d\n", sizeof(A));//打印 1 printf("C++中空类内存大小是%d\n", sizeof(B)); //打印1 //在C++中,空结构体,空类都在内存中占一个字节大小的内存空间 system(&qu

go 语言学习笔计之结构体

go 语言中的结构体方法 结构体名称的大小写有着不同的意义: 小写表示不能被别的包访问 package main import "fmt" type Rect struct { width,height int } func (r *Rect) area() int { return r.width*r.height; } func main() { r:=Rect{width:10,height:10} fmt.Println(r.area()); rp:=&r; fmt.P

c语言_文件操作_FILE结构体小解释

参考文档来自:https://www.cnblogs.com/haore147/p/3648395.html 我们通过fopen返回一个文件指针(指向FILE结构体的指针)来进行文件操作. 在vs2013下的代码如下: #include <stdio.h> #pragma warning(disable:4996) int main() { FILE *p = fopen("C:\\test\\win\\a.txt", "r"); char buf[10

GO语言编程基础-复合类型结构体

大家好,我们是链客区块链技术问答社区,今天讲一讲Go语言的基础编程. 链客,有问必答!!! 1 结构体类型 有时我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别/年龄/地址等属性.显然单独定义以上变量比较繁琐,数据不便于管理. 结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合.每个数据称为结构体的成员. 2 结构体初始化 2.1 普通变量 type Student struct { id   int name string sex  

STM32——C语言知识点:指针、结构体

1 /* 2 ============================================================================ 3 Name : Cyuyanfuxi.c 4 Author : 5 Version : 6 Copyright : Your copyright notice 7 Description : Hello World in C, Ansi-style 8 ======================================

C语言-06复杂数据类型-04 结构体

结构体的说明(构造类型) 数组:只能由多个相同类型的数据构成 结构体:可以由多个不同类型的数据构成 ,结构体的类型是不存在的,自己定义 int main() { // 1.定义结构体类型 定义类型的时候是没有分配内存的 struct Person { // 里面的3个变量,可以称为是结构体的成员或者属性 int age; // 年龄 double height; // 身高 char *name; // 姓名 }; //注意分号 // 1.定义结构体类型 struct Person p = {2