因为简单的表达式生成的新切片于原数组或者切片共享底层的数组避免了拷贝元素,节约内存空间的同时也会带来一定的风险。
新切片b ( b := a[low, high])不仅可以读写a[low]至a[high-1]之间的所有元素,而且在使用append(b, x)函数增加新的元素x时,还可能会覆盖a[high]及后面的元素。例如:
a:-[5]int{1,2,3,4,5}
b:= a[1:4]
b = append(b,0)//此时元素a[4]将由5变为0
使用新切片覆盖a[high]及后面的元素,有可能是非预期的,从而产生灾难性的后果。
Go团队很早就关注到了这个风险,并且在Go 1.2中就提供了一种可以限制新切片容量的表达式,即扩展表达式:
a[low : high : max]
扩展表达式中的max用于限制新生成切片的容量,新切片的容量为max - low,表达式中的low、high和 max需要满足以下关系:
0≤ low ≤ high ≤ max ≤ cap(a)
对于一个长度为10的数组,使用扩展表达式切取其两个元素生成的新切片的拓扑结构如下图所示。
array := [10]int
slice := array[5:7:7]
如果使用简单表达式,那么上图中切片的容量将为5,而使用扩展表达式时切片的容量则被限制为2。
扩展表达式常见于偏底层的代码中,比如 Go源代码。扩展表达式生成的切片将被限制存储容量,笔者习惯上称其为被“封印”的切片。当使用 append()函数向被“封印”的切片追加新元素时,如果存储容量不足则会产生一个全新的切片,而不会覆盖原始的数组或切片。
扩展表达式中的a [low : high : max]只有low是可以省略的,其默认值为0。这一点与简单表达式略有不同。
如果缺失了high或max则会产生编译错误:
middle index required in 3-index slice //缺失high
final index required in 3-index slice //缺失max
小结:
slice表达式分为简单表达式a[low,high]和扩展表达式a[low : high : max];
简单表达式作用于数组、切片时产生新的切片,作用于字符串时产生新的字符串;
扩展表达式只能作用于数组、切片,不能作用于字符串。