数组
数组是具有固定长度且拥有零个或多个相同数据类型元素的序列
由于数组固定长度,因此用的比较少,slice的长度是动态的,用的更多
初始化
- 默认初始化为元素类型的零值
var a [3]int
- 省略号出现在数组长度的位置,那么数组的长度由初始化的元素个数决定
q := [...]int{1, 2, 3}
fmt.Println("%T\n", q) // "[3]int"
- 通过指定索引初始化
// 定义了一个拥有100个元素的数组r,除了最后一个元素值是-1外,该数组中的其他元素值都是0
r := [...]int{99: -1}
比较
如果一个数组的元素是可比较的,那么这个数组也是可比较的,即可以用==
或!=
操作符比较
数组的长度是数组类型的一部分,因此[3]int
和[4]int
是两种不同的数组类型
数组作为函数参数
Go语言中与C\C++中一个很大不同是,数组是值传递,而不是引用传递
就是调用一个函数时,每个传入的参数都会创建一个副本,函数内改变的数副本,而不是原始数据
当然也可以用数组指针
slice
slice表示一个拥有相同类型的可变长度的序列
slice有三个属性:指针、长度和容量
- 指针指向数组的第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素
- 长度是指slice中的元素个数,它不能超过slice的容量
- 容量的大小通常是从slice的起始元素到底层数组的最后一个元素间元素的个数
Go的内置函数len
和cap
用来返回slice的长度和容量
一个底层数组可以对应多个slice,这些slice可以引用数组的任何位置
slice作为函数参数
因为slice包含了指向数组元素的指针,所以一个slice传递给函数的时候,可以在函数内部修改底层数组的元素
就是创建一个slice等于为数组创建了一个别名
比较
与数组不同的是,slice无法做比较
标准库中有bytes.Equal
来比较两个字节slice([]byte),但是对于其他类型的slice就需要自己写函数比较
slice唯一允许的比较操作是和nil
做比较
slice类型的零值是nil
,值为nil
的slice没有对应的底层数组,长度和容量都是零
但是也有非nil
的slice长度和容量是零
因此如果要检查一个slice是否为空,使用len(s) == 0
,而不是s == nil
make
内置函数make
可以创建一个具有指定元素类型、长度和容量的slice,其中容量参数可以省略,在这种情况下,slice的长度和容量相等
make([]T, len)
make([]T, len, cap)
其实make
创建了一个无名数组并返回了它的一个slice,这个数组仅可以通过这个slice来访问
append函数
内置函数append
用来将元素追加到slice的后面
通常情况下,我们不清楚一次append
调用会不会导致一次新的内存分配,
所以我们不能假设原始的slice和调用append后的结果slice指向同一个底层数组,
同样我们也无法假设旧slice对元素的操作会或者不会影响新的slice元素
所以,通常我们将append的调用结果,再次复制给传入append
函数的slice
runes = append(runes, r)
不仅仅是调用append
函数的情况下需要更新slice变量,对于任何函数只要有可能改变slice的长度或者容量,
抑或是使得slice指向不同的底层数组,都需要更新slice变量
总结
- 数组是具有固定长度且拥有零个或多个相同数据类型元素的序列
- 数组是值传递,而不是引用传递
- slice表示一个拥有相同类型的可变长度的序列
- 与数组不同的是,slice无法做比较
- slice类型的零值是
nil
,值为nil
的slice没有对应的底层数组,长度和容量都是零 - 如果要检查一个slice是否为空,使用
len(s) == 0
,而不是s == nil