Slice是Go语言提供的一种方便并且高效的有序数据类型,就和其他语言的数组类似,但是又有一些其他的特性。
Go数组:
因为Slice是建立在Go数组的抽象层上的,所以,要学习Slice,我们先来看一下Go语言的数组:
一个数组定义了一个具有特定长度和数据类型的数据。例如:【4】int 就代表了一个有4个int类型的数组。数组的大小是确定的,数组的长度是数组类型的一部分(【4】int和【5】int是完全不同的类型)。数组可以像其他语言那样索引,s【n】能够访问第n个元素:
var a [4]int a[0] = 1 i := a[0] // i == 1数组不需要明确的初始化,没有初始化的项,将用0作为默认值
// a[2] == 0, the zero value of the int type【4】int的内存结构如下图:
Go语言的数组是值定义的,而不是指针。一个数组变量就代表了整个数组,而不是一个指向第一个数组元素的指针(像c语言那样)。这就意味着,当需要传递一个数组的时候,我们应该传递这个数组的整个内容,也就是拷贝这个数组的整个内容。(为了避免拷贝的麻烦,我们可以传递一个指向数组的指针,但是需要注意的是:这样做了之后,这个指针就仅仅是一个指针而已,而不是一个数组)
一个字符串数组可以这样定义:
b := [2]string{"Penn", "Teller"}或者,可以让编译器帮我们统计元素的个数:
b := [...]string{"Penn", "Teller"}这两种方法都是等价的。
Slices:
letters := []string{"a", "b", "c", "d"}
slice也可以用Go内部库函数make来创建,make是具有签名功能的:
func make([]T, len, cap) []T
T表示元素的类型,make函数有3个参数,T元素的类型,len长度,cap容量(cap可选)。当make被调用的时候,make分配一下数组并且返回一个根据这个数组生产的slice。如果不填写cap,那么默认的情况下cap=len,一种简洁的make的写法是:
s := make([]byte, 5)
可以用Go的库函数,len和cap来获取slice的len和cap:
len(s) == 5 cap(s) == 5
slice的0值为nil,如果一个slice等于nil,那么len和cap都会返回0.
我们同样可以用一个已经存在的数组或者slice来创建一个新的slice,例如:
a :=b【n:m】,表示a取b中从n到m-1的元素。
例如:
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'} // b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b
获取Slice片段的时候,默认的开始值是0,默认的结束是该slice的长度,例如:
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
b[:2] == []byte{'g', 'o'} b[2:] == []byte{'l', 'a', 'n', 'g'} b[:] == b
同样的,slice也可以用数组来创建:
x := [3]string{"Лайка", "Белка", "Стрелка"} s := x[:] // a slice referencing the storage of x
slice的存储结构:
一个slice描述了一个数组的片段,一个slice包括:指向数组的指针,该段的长度,容量(段的最大长度)
s := make([]byte, 5)的存储结构如下:
再次明确一下,len是slice中item的个数,cap是slice所指向的数组的长度(从slice所指向的开始的位置开始,直到数组结尾),例如:
s = s[2:4]
在slice的基础上创建新的slice,并不是做赋值操作,而是创建了一个新的指向相同数组的slice,例如:
d := []byte{'r', 'o', 'a', 'd'} e := d[2:] // e == []byte{'a', 'd'} e[1] = 'm' // e == []byte{'a', 'm'} // d == []byte{'r', 'o', 'a', 'm'}
有疑问加站长微信联系(非本文作者)