Go 通过类型别名(alias types)和结构体的形式支持用户自定义类型。

结构体是复合类型,当需要定义类型,它由一系列属性组成,每个属性都有自己的类型和值的时候,就应该使用结构体,它把数据聚集在一起。

结构体也是值类型,因此可以通过 new 函数来创建

组成结构体类型的那些数据成为字段(fields)。每个字段都有一个类型和一个名字;在一个结构体中,字段名字必须是唯一的。

一,结构体定义

结构体定义的一般方式如下:

type identifier struct {
field type1
field type2
}

type T struct {a, b int} 也是合法的语法,它更适用于简单的结构体

结构体里的字段都有 名字,像 field1、field2 等,如果字段在代码中从来也不会被用到,那么可以命名它为 _。

结构体类型和字段的命名遵循可见性规则,所以可能存在一个结构体类型的某些字段是导出的,而另一些没有导出。

结构体的字段可以是任何类型,甚至是结构体本身,也可以是函数或者接口。可以声明结构体类型的一个变量,然后像下面这样给它的字段赋值:

var s T
s.a = 5
s.b = 8

数组也可以看作是一种结构体类型,不过它使用下标而不是具名的字段

二,初始化

方式一:通过 var 声明结构体

在 Go 语言中当一个变量被声明的时候,系统会自动初始化它的默认值,比如 int 被初始化为 0,指针为 nil。

var 声明同样也会为结构体类型的数据分配内存,所以我们才能像上一段代码中那样,在声明了 var s T 之后就能直接给他的字段进行赋值

方式二:使用 new

使用 new 函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:var t *T = new(T)。

type struct1 struct {
i1 int
f1 float32
str string
} func main() {
ms := new(struct1)
ms.i1 = 10
ms.f1 = 15.5
ms.str= "Chris" fmt.Printf("The int is: %d\n", ms.i1)
fmt.Printf("The float is: %f\n", ms.f1)
fmt.Printf("The string is: %s\n", ms.str)
fmt.Println(ms)
}

与面向对象语言相同,使用点操作符可以给字段赋值:structname.fieldname = value

同样的,使用点操作符可以获取结构体字段的值:structname.fieldname

方式三:使用字面量

type Person struct {
name string
age int
address string
} func main() {
var p1 Person
p1 = Person{"lisi", 30, "shanghai"} //方式A
p2 := Person{address:"beijing", age:25, name:"wangwu"} //方式B
p3 := Person{address:"NewYork"} //方式C
}

在(方式A)中,值必须以字段在结构体定义时的顺序给出。(方式B)是在值前面加上了字段名和冒号,这种方式下值的顺序不必一致,并且某些字段还可以被忽略掉,就想(方式C)那样。

除了上面这三种方式外,还有一种初始化结构体实体更简短和常用的方式,如下:

ms := &Person{"name", 20, "bj"}
ms2 := &Person{name:"zhangsan"}

&Person{a, b, c} 是一种简写,底层仍会调用 new(),这里值的顺序必须按照字段顺序来写,同样它也可以使用在值前面加上字段名和冒号的写法(见上文的方式B,C)。

表达式 new(Type)&Type{} 是等价的。

三,几种初始化方式之间的区别

到目前为止,我们已经了解了三种初始化结构体的方式:

//第一种,在Go语言中,可以直接以 var 的方式声明结构体即可完成实例化
var t T
t.a = 1
t.b = 2 //第二种,使用 new() 实例化
t := new(T) //第三种,使用字面量初始化
t := T{a, b}
t := &T{} //等效于 new(T)

使用 var t T 会给 t 分配内存,并零值化内存,但是这个时候的 t 的类型是 T

使用 new 关键字时 t := new(T),变量 t 则是一个指向 T 的指针

从内存布局上来看,我们就能看出这三种初始化方式的区别:

使用 var 声明:

使用 new 初始化:

使用结构体字面量初始化:

下面来看一个具体的例子

package main
import "fmt" type Person struct {
name string
age int
} func main() {
var p1 Person
p1.name = "zhangsan"
p1.age = 18
fmt.Printf("This is %s, %d years old\n", p1.name, p1.age) p2 := new(Person)
p2.name = "lisi"
p2.age = 20
(*p2).age = 23 //这种写法也是合法的
fmt.Printf("This is %s, %d years old\n", p2.name, p2.age) p3 := Person{"wangwu", 25}
fmt.Printf("This is %s, %d years old\n", p3.name, p3.age)
}

输出:

This is zhangsan, 18 years old
This is lisi, 23 years old
This is wangwu, 25 years old

上面例子的第二种情况,虽然 p2 是指针类型,但我们仍然可以像 p2.age = 23 这样赋值,不需要像 C++ 中那样使用 -> 操作符,Go 会自动进行转换。

注意也可以先通过 * 操作符来获取指针所指向的内容,再进行赋值:(*p2).age = 23

结构体的内存布局

Go 语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体,这在性能上带来了很大的优势。不像 Java 中的引用类型,一个对象和它里面包含的对象可能会在不同的内存空间中,这点和 Go 语言中的指针很像。下面的例子清晰地说明了这些情况:

type Rect1 struct {Min, Max Point }
type Rect2 struct {Min, Max *Point }

Go 结构体与初始化的更多相关文章

  1. C语言一维数组、二维数组、结构体的初始化

    C语言数组的初始化表示方法 一.C语言一维数组初始化: (1)在定义数组时对数组元素赋以初值.如: static int a[10]={0,1,2,3,4,5,6,7,8,9}; 经过上面的定义和初始 ...

  2. C语言结构体的初始化

    今天在工作时,看到了奇葩的结构体初始化方式,于是我查了一下C99标准文档和gcc的说明文档,终于搞清楚是怎么回事了. 假设有如下结构体定义: typedef struct { int a, b, c; ...

  3. (转)关于linux中内核编程中结构体的赋值操作(结构体指定初始化)

    网址:http://blog.chinaunix.net/uid-24807808-id-3219820.html 在看linux源码的时候,经常会看到类似于下面的结构体赋值的代码: struct d ...

  4. FFmpeg源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  5. [转载] FFmpeg源代码简单分析:常见结构体的初始化和销毁(AVFormatContext,AVFrame等)

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  6. 关于c语言中结构体的初始化

    1.先定义结构体类型后再定义结构体变量: 格式为:struct 结构体名 变量名列表: struct book s1,s2,*ss://注意这种之前要先定义结构体类型后再定义变量: 2.在定义结构体类 ...

  7. 浅谈C语言中结构体的初始化

    转自:http://www.jb51.net/article/37246.htm <代码大全>建议在变量定义的时候进行初始化,但是很多人,特别是新人对结构体或者结构体数组定义是一般不会初始 ...

  8. C基础--结构体成员初始化方式

    之前在linux内核代码中看到结构体成员成员初始化使用类似于.owner = THIS_MODULE, 不太见过,于是搜了个博客,分享下: 转自:http://www.cnblogs.com/Anke ...

  9. c语言结构体指针初始化

    今天来讨论一下C中的内存管理. 记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面 我说所有指针使用前都必须初始化,结构体中的成员指针也是一样 有人反驳说,不是吧,以前做二叉树算法时,他的左 ...

  10. C语言结构体指针初始化(转)

    reference: https://www.cnblogs.com/losesea/archive/2012/11/15/2772526.html 今天来讨论一下C中的内存管理. 记得上周在饭桌上和 ...

随机推荐

  1. 封装一些简单的 dom 操作

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  2. Django基础第一篇

    目录 1.Django MTV框架简介 2.基础命令创建项目的配置说明 3.前后端交互案例 4.基于数据库实现数据交互增删改查 Django简介 Django框架的设计模式借鉴了MVC的思想,和MVC ...

  3. Python字符串、组合数据类型练习

    一.Python字符串练习 1.http://news.gzcc.cn/html/2017/xiaoyuanxinwen_1027/8443.html 取得校园新闻的编号. (这个方法就很多了,一般方 ...

  4. js小功能3:一个简单的计算器功能

    html: <input type='text' id='txt1' /> <select id='select'> <option value='+'>+< ...

  5. Java高并发程序设计学习笔记(三):Java内存模型和线程安全

    转自:https://blog.csdn.net/dataiyangu/article/details/86412704 原子性有序性可见性– 编译器优化– 硬件优化(如写吸收,批操作)Java虚拟机 ...

  6. go语言入门(3)运算符及流程控制

    1,运算符 算数运算符:+   -   *   /   %   ++   -- 关系运算符:==    !=    <    >    <=    >== 逻辑运算符:按位与 ...

  7. 如何解决Win10系统更新显示0x80080300代码的错误?

    Win10系统自推出以来就不断的在完善更新,其越来越丰富的功能也吸引了越来越多的用户.好系统Win10系统:https://www.vkebao.com/os/index_2.html但最近有用户反映 ...

  8. 第十三章·Kibana深入-使用地图统计客户端IP

    地址库 在ELK中,我们可以使用地址库,来对IP进行分析,对日志进行分析,在ELKstack中只有Logstash可以做到,但是出图,是Kibana来出的,所以我们首先需要下载地址库数据文件,然后对L ...

  9. 用Nginx为多个http/socks代理做负载均衡(反向代理)

    近日遇到一个需求,某机器上在四个端口上开了四个http代理,因为每个代理都有流量限额,所以要平均着使用,但由使用者手动更改端口号又太麻烦,所以需要将这4个端口融合为1个,想到的办法就是用Nginx做负 ...

  10. ISO/IEC 15444-12 MP4 封装格式标准摘录 5

    目录 Segments Segment Type Box Segment Index Box Subsegment Index Box Producer Reference Time Box Supp ...