hakeの日記

Windows環境でプログラミングの勉強をしています。

Go言語 - スライス

Go言語では一旦作成された配列の要素数は変更できない。スライスは配列への参照だけれども要素数の変更は可能。スライスに要素が追加されて、配列のキャパシティを超えた場合には、より大きなキャパシティを持った配列と、そのスライスが作成されて要素の値がコピーされる。
従って、二つの変数が同じスライスを参照していて、一方の要素をキャパシティ以上に増やした場合には、その変数は新しいスライスを参照することになる。

package main

import "fmt"

func main() {

	a := make([]int, 8, 8)
	a[7] = 9
	b := a
	b[6] = 8

	// a と b は、同じスライス。
	fmt.Println(a)       // -> [0 0 0 0 0 0 8 9]
	fmt.Println(len(a))  // -> 8 要素数
	fmt.Println(cap(a))  // -> 8 キャパシティ

	fmt.Println(b)       // -> [0 0 0 0 0 0 8 9]
	fmt.Println(len(b))  // -> 8
	fmt.Println(cap(b))  // -> 8


	// a に1要素追加
	// 要素数がキャパシティを超えた為、新しい配列のスライスになる。
	a = append(a, 10)

	// a と b は、異なるスライス
	a[0] = 1
	fmt.Println(a)       // -> [1 0 0 0 0 0 8 9 10]
	fmt.Println(len(a))  // -> 9
	fmt.Println(cap(a))  // -> 16

	fmt.Println(b)       // -> [0 0 0 0 0 0 8 9]
	fmt.Println(len(b))  // -> 8
	fmt.Println(cap(b))  // -> 8


}

スライスは参照

スライスは実体の配列への参照なので、関数の引数で渡した場合は参照がそのまま渡される。
従って関数の中でスライスの要素を変更した場合は、元のスライスも変更される。ただし要素数を変更した場合は、関数内で新しいスライスが生成されるため、元のスライスに影響を与えない。

package main

import "fmt"

func incInt(i *int){
	*i++            // 関数外の実体を変更する場合はポインタ指定が必要
}

func incSlice(lis []int, idx int){
	lis[idx]++                   // 元のスライスも変更される

	lis = append(lis, 100)       // 要素を追加
	fmt.Println(lis)             //-> [1 3 3 100]
}                                    // 新規スライスが作成されるので
                                     //   元のスライスに影響なし

func main() {
	var i int = 1
	fmt.Println(i)      //-> 1
	incInt(&i)
	fmt.Println(i)      //-> 2

	s := []int{1,2,3}
	fmt.Println(s)      //-> [1 2 3]
	incSlice(s, 1)
	fmt.Println(s)      //-> [1 3 3]

}