复合数据类型
数组
- 长度固定,有零个或者多个元素组成。
- 默认情况下,数组的每个元素都被初始化为元素类型零值。
- 如果数组的长度位置出现
...
,则表示数组长度是根据初始值的个数来计算。如:q := [...]int{1, 2, 3}
- 如果指定索引和对应值列表的方式初始化,这种情形下初始化索引的顺序是无关紧要的,而且没有用到的索引可以省略,未指定初始值的元素将使用零值初始化。如:
r := [...]int{99: -1}
定义了一个含有100个元素的数组。 - 如果一个数组的元素类型是可以比较的,那么数组类型也是可以比较的,可以使用
==
、!=
来进行比较,仅当数组长度和元素完全相等时,为true
。长度不相等的数组进行等值对比是会报编译错误compile error: cannot compare [2]int == [3]int
slice
- 变长序列,序列中每个元素都有相同的类型。一个
slice
类型一般写作[]T
,其中T
代表slice
中的类型。 - 由指针、长度、容量构成。指针指向第一个
slice
元素对应的底层数组元素的地址(PS:slice
的第一个元素并不一定就是数组的第一个元素)。长度对应slice
的元素数目,长度不能超过容量。容量一般是从slice
的开始位置到底层数据的结尾位置。内置的len
和cap
分别返回slice
的长度和容量。 - 多个
slice
之间可以共享底层的数据,并且引用的数组部分区间可能重叠。 slice
之间不能比较,意味着不能使用==
、!=
操作符来进行判断两个切片是否含有全部相等的元素。标准库中提供了bytes.Equal
函数来判断两个字节型切片是否相等([]byte),对于其他类型的切片需要我们自己来展开比较。
切片不支持比较的原因:
- 切片元素是间接引用的,一个切片甚至可以包含自身(当
slice
声明为[]interface{}
时,slice
的元素可以是自身) - 因为
slice
元素是间接引用的,一个固定的slice
值(指slice
本身的值,不是元素的值)在不同时刻可能包含不同元素,因为底层数组的元素可能会被修改。
- 切片元素是间接引用的,一个切片甚至可以包含自身(当
slice
唯一合法的比较操作是和nil
做比较(if summer == nil { /* ... */ }
)。
零值的
slice
等于nil
。
nil
值的slice
没有底层数组
nil
值的slice
的长度和容量都是0
。但是也有非nil
值的slice
的长度和容量为0
的,如[]int{}
、make([]int, 3)[3:]
。可以用[]int(nil)
类型转换表达式来生成一个对应类型的slice
的nil
值。var s []int // len(s) == 0, s == nil s = nil // len(s) == 0, s == nil s = []int(nil) // len(s) == 0, s == nil s = []int{} // len(s) == 0, s != nil
- 如果要测试一个
slice
是否是空的,使用len(s) == 0
来判断,而不是s == nil
。 - 内置的
make
函数可以创建指定类型、长度和容量的切片。容量部分可以省略,这种情况下,容量等于长度。make([]T, len, cap)
- 尽管底层数组的元素是间接访问的,但是
slice
对应结构体本身的指针、长度和容量部分都是直接访问的。一般操作slice
后会重新赋值给变量。如:runes = append(runes, r)
appendInt
参数的省略号...
代表接受变长的参数为slice
func appendInt(x []int, y ...int) []int { var z []int zlen := len(x) + len(y) // ...expand z to at least zlen... copy(z[len(x):], y) return z }
- 要删除slice中间的某个元素并保存原有的元素顺序,可以通过内置的copy函数将后面的子slice向前依次移动一位完成
func remove(slice []int, i int) []int { copy(slice[i:], slice[i+1:]) return slice[:len(slice)-1] }
如果删除元素后不用保持原来顺序的话,我们可以简单的用最后一个元素覆盖被删除的元素
func remove(slice []int, i int) []int { slice[i] = slice[len(slice)-1] return slice[:len(slice)-1] }
文章评论