复合数据类型
主要有四种复合数据类型:数组、slice、map和结构体。数组和结构体是具有固定大小的数据结构,slice和map是动态的数据结构,它们将根据需要动态增长。
数组
数组默认会生成0~数组长度-1
的索引,于是便可以通过下标索引到数组对应元素值,也可以指定一个索引和对应值列表的方式初始化:
|
|
在这种形式的数组字面值形式中, 初始化索引的顺序是无关紧要的, 而且没用到的索引可以省略, 和前面提到的规则一样, 未指定初始值的元素将用零值初始化。
数组在实际编程中其实用的很少.
Slice
Slice代表变成的序列,序列中每个元素具有相同的类型。slice的语法与数组很像,只是没有固定长度。
|
|
如果是数组的话:
|
|
Slice底层是靠数组实现的。一个slice是一个轻量级的数据结构,包括三个部分:指针、长度、容量。
指针指向第一个slice元素对应的底层数组元素的地址, 要注意的是slice的第一个元素并不一定就是数组的第一个元素。 长度对应slice中元素的数目;长度不能超过容量, 容量一般是从slice的开始位置到底层数据的结尾位置。 内置的len
和cap
函数分别返回slice的长度和容量。
多个slice之间可以共享底层的数据, 并且引用的数组部分区间可能重叠。
我们首先定义一个数组:
|
|
我们声明数组时直接跳过第0个元素, 第0个元素会被自动初始化为空字符串。
|
|
如果切片操作超出cap(s)
的上限将导致一个panic
异常, 但是超出len(s)
则是意味着扩展slice, 因为新slice的长度会变大:
|
|
内置的make
函数创建一个指定元素类型、 长度和容量的slice。 容量部分可以省略, 在这种情况下, 容量将等于长度。
|
|
内置的append
函数用于向slice追加元素:
|
|
Map
map类型可以写为map[K]V
, 其中K
和V
分别对应key和value。 map中所有的key都有相同的类型, 所有的value也有着相同的类型, 但是key和value之间可以是不同的数据类型。 其中K
对应的key必须是支持==
比较运算符的数据类型, 所以map可以通过测试key是否相等来判断是否已经存在。
内置的make
函数可以创建一个map:
|
|
我们也可以用map
字面值的语法创建map, 同时还可以指定一些最初的key/value:
|
|
这相当于;
|
|
因此, 另一种创建空的map的表达式是 map[string]int{}
。
要想遍历map中全部的key/value对的话, 可以使用range
风格的for循环实现:
|
|
map下标语法也可以返回两个值:
|
|
在这种场景下, map的下标语法将产生两个值;第二个是一个布尔值, 用于报告元素是否真的存在。 布尔变量一般命名为ok, 特别适合马上用于if条件判断部分。
结构体
例子:
|
|
通常一行对应一个结构体成员, 成员的名字在前类型在后, 不过如果相邻的成员类型如果相同的话可以被合并到一行, 就像下面的Name
和Address
成员那样:
|
|
结构体值也可以用结构体面值表示, 结构体面值可以指定每个成员的值。
|
|
上面是初始化结构体的一种方式,但是这要求按顺序初始化结构体中的全部字段,另外一种方法是,以成员名字和相应的值来初始化, 这样可以包含部分或全部的成员,这也是常用的方式.
Go语言的结构体支持匿名成员,匿名成员的数据类型必须是命名的类型或指向一个命名的类型的指针。
|
|
得意于匿名嵌入的特性, 我们可以直接访问叶子属性而不需要给出完整的路径:
|
|
编组
将结构体slice转为JSON的过程叫编组(marshaling)
我们首先定义一个Movie
结构体,然后创建数组:
|
|
|
|
将会产生以下输出:
|
|
只有导出的结构体成员才会被编码, 这也就是我们为什么选择用大写字母开头的成员名称。
可以看到, 其中Year
名字的成员在编码后变成了released
, 还有Color
成员编码后变成了小写字母开头的color
。 这是因为构体成员Tag所导致的。 一个构体成员Tag是和在编译阶段关联到该成员的元信息字符串:
|
|
成员Tag中json对应值的第一部分用于指定JSON对象的名字.Color
成员的Tag还带了一个额外的omitempty
选项, 表示当Go语言结构体成员为空或零值时不生成JSON对象(这里false为零值)。
解组
编组的逆操作,需要先定义合适的结构体,然后使用json.Unmarshal()
函数对json数据进行解组,具体就不介绍了。
重点
x[m:n]
切片操作对于字符串则生成一个新字符串- 一个零值的slice等于
nil
。 一个nil
值的slice并没有底层数组。 一个nil
值的slice的长度和容量都是0, 但是也有非nil
值的slice的长度和容量也是0的, 例如[]int{}
或make([]int, 3)[3:]
。 - 如果你需要测试一个slice是否是空的, 使用
len(s) == 0
来判断, 而不应该用s == nil
来判断。