読者です 読者をやめる 読者になる 読者になる

Go言語:スライス

スライスの話(go-tourは、なぜかArrayをとばしてSliceの話をする)

SliceとArrayは異なる。こちらを参照してお勉強。

あとはこちらのSlideShareを参照する。

Array

  • Go言語のArrayは長さ要素の型を明らかにしたもの
    • 値である。(C言語とは異なる。)
    • Go言語の基本が値渡しになるので、避けるには、Array全体に対してのポインターを渡す。
  • Arrayの初期化は構造体とだいたい同じ。
    • [要素数]型{ 初期化する値 }
    • 素数が必要。[2]intみたいな。
    • 素数を省略してコンパイラに委ねる場合は、[...]intのようにする。
    • 初期化子に値が渡されなかったインデックスは、zero valueで初期化される。(intなら0とか、stringなら空文字とか)

Slice

  • Arrayの抽象的なもの(らしい)(抽象的とは?)
    • Go言語ではArrayはあまり使われずに、Sliceが使われる。
  • Sliceは、Arrayへのポインター長さ容量で構成される。
    • Arrayへのポインターを持っているので、要素を変更すると、参照元に影響がある。
    • 長さは、Array自体の長さ。
  • Sliceの初期化は、Arrayのそれとだいたい同じ。
    • []型{ 初期化する値 }
    • 素数がいらない。...も書かない。
  • 初期化時に値が渡されない場合、nilになる。
    • nilの長さは、0。
    • nilの容量は、0。
  • 初期化の文法を使わずに、make関数を使うことでも作成可能。
    • make([]T, len, cap)
    • capを省略した場合は、len == capになる。
    • caplenよりも短い場合、エラーする。
    • lenで指定された長さ分(0からlen個分)の要素がzero valueで初期化される。
  • len以内の要素の操作
    • slice[2]slice[1] = 2のように操作可能。
    • 代入は(当然ながら)破壊的。
  • lenを超える要素(というかインデックス)の操作
    • slice[5]のような操作をするとpanic。
    • 要素を追加するには、appendを使う。
    • append( slice, T... ) []T
    • appendは破壊的ではない。
    • `容量を超える量を追加しようとすると、自動的に容量を追加してくれる。
  • 再スライス可能。
    • 部分的に取り出して、別のスライスにする。
    • 配列部分はポインターなので、別のスライスになっても、同じメモリ領域をみている。
  • スライスのインデックスの取り出し方。
    • slice[ : ] -> すべての要素のスライス。
    • slice[ lo:hi ] ->lo番目からhi - 1`番目の要素のスライス。
    • slice[ lo: ] -> lo番目以降の要素のスライス。
    • slice[ :hi ] -> hi - 1番目までの要素のスライス。
  • 要素を削除する関数は用意されていない。

Array

以下の様な感じ。

func main() {
  ary1 := [3]string{ "dog", "cat" }
  fmt.Println( ary1 )
  fmt.Println( ary1[0] )
  fmt.Println( ary1[1] )
  fmt.Println( ary1[2] )

  ary2 := [3]int{ 10, 20 }
  fmt.Println( ary2 )
  fmt.Println( ary2[0] )
  fmt.Println( ary2[1] )
  fmt.Println( ary2[2] )

  // fmt.Println( ary2[3] )
}

//=>
// [dog cat ]
// dog
// cat
// 
// [10 20 0]
// 10
// 20
// 0

コメントアウトしている行を解くと、

invalid array index 3 (out of bounds for 3-element array)
 [process exited with non-zero status]

slice

基本的な操作を試してみる。

func main() {
  var sl0 []int
  fmt.Println( sl0 )
  fmt.Println( len( sl0 ) )
  fmt.Println( cap( sl0 ) )

  sl1 := make([]int, 5)
  fmt.Println( sl1 )
  fmt.Println( len( sl1 ) )
  fmt.Println( cap( sl1 ) )

  sl2 := make([]int, 5, 8 )
  fmt.Println( sl2 )
  fmt.Println( len( sl2 ) )
  fmt.Println( cap( sl2 ) )

  sl2[4] = 1

  fmt.Println( sl2 )
  fmt.Println( sl2[4] )
  // fmt.Println( sl2[5] )

  sl3 := append( sl2, 3, 4, 5, 6 )

  fmt.Println( sl2 )
  fmt.Println( len( sl2 ) )
  fmt.Println( cap( sl2 ) )

  fmt.Println( sl3 )
  fmt.Println( len( sl3 ) )
  fmt.Println( cap( sl3 ) )
}

//=>
// []
// 0
// 0
// [0 0 0 0 0]
// 5
// 5
// [0 0 0 0 0]
// 5
// 8
// [0 0 0 0 1]
// 1
// [0 0 0 0 1]
// 5
// 8
// [0 0 0 0 1 3 4 5 6]
// 9
// 16

コメントアウトしている行を解くと、

panic: runtime error: index out of range
 [process exited with non-zero status]

slicing slices

スライス:スライシング

[10 20 30 40 50 60 70 80 90]
[40 50 60 70]
[60 70 80 90]
[40 50 60]
[10 20 30 40 51 60 70 80 90]
[40 51 60 70]
[60 70 80 90]
[40 51 60]
[10 20 30 40 52 60 70 80 90]
[40 52 60 70]
[60 70 80 90]
[40 52 60]