TL;DR

Go でスライシングするときに、結果のスライスのキャパシティも指定する記法。a[low:high:max] と書く。

なぜ必要か

100 Go Mistakes and How to Avoid Them によると、append による予期せぬ副作用を避けるために使う。

仕組み

a[low:high:max] は、長さと要素が a[low:high] と同じスライスを作る。違うのは、キャパシティが max - low になる点だけである。インデックスは 0 <= low <= high <= max <= cap(a) を満たす必要があり、省略できるのは low だけである。また、文字列には使えない。

例

次のコードでは、main の s と f に渡したスライスが同じ基底配列を参照している。s[:2] のキャパシティは 3 なので、f の中の append は基底配列の 3 番目の要素を書き換え、その変更が main にも表れる。

func main() {
	s := []int{1, 2, 3}
	f(s[:2])
	fmt.Println(s) // [1 2 100]
}
 
func f(s []int) {
	_ = append(s, 100)
}

完全スライス式でキャパシティを 2 に制限すると、append は新しい配列を確保するので、main の s は変わらない。

func main() {
	s := []int{1, 2, 3}
	f(s[:2:2])
	fmt.Println(s) // [1 2 3]
}
 
func f(s []int) {
	_ = append(s, 100)
}

関連

出典