Golangのスライス(slice)とは
スライスはサイズ変更可能な配列であり、それを扱う際に非常に大きな柔軟性を提供します。
Golangにおいて配列(array)とは、サイズ変更が不可の配列であり、RubyやJavaScript等での「配列」とは異なる特徴があります。
なので、RubyやJavaScript等での「配列」はGolangではスライス(slice)ということになります。
スライス(slice)の定義・宣言
スライスは配列と同じように宣言されますが、その要素数には言及しません。
package main
func main() {
var sampleSlice []string // 文字列のスライス
}
スライス(slice)と配列(array)の違い
Golangにおける、スライスと配列の違いは以下の通りです
- 配列は要素数が指定されて宣言された後、要素数を変更することができませんが、スライスは要素数を変更することができる。
- スライスは参照型であるのに対し、配列は値型である。
Golangでスライスを作成する
スライスを作成する方法はいくつかあります。
sliceリテラル構文の使用
スライスリテラルは、スライスの初期化構文です。
以下は、スライスリテラルの構文を使用してスライスを作成する例です。
package main
import "fmt"
func main() {
var stringSlice = []string{"I", "like", "banana"}
fmt.Println(stringSlice) // [I like banana]
}
配列からスライスを作成する
スライスは配列への参照を持っています。ですから、配列から作成することは難しくありません。
以下の書式だと配列からスライスを作成することができます。
配列[始まりのインデックス番号:終わりのインデックス番号]
上記の方法でスライスを作成する具体的なコード例は以下になります。
package main
import (
"fmt"
)
func main() {
var arr = [7]int{1, 2, 3, 4, 5, 6, 7}
var arrSlice = arr[1:5]
fmt.Println(arrSlice) // [2 3 4 5]
}
他のスライスからスライスを作成する
スライスは、そのスライスを切り取ることで、他のスライスから作成することができます。
package main
import "fmt"
func main() {
var oddNumbers = [9]int{1, 3, 5, 7, 9, 11, 13, 15, 17}
slice1 := oddNumbers[4:]
fmt.Println(slice1) // [9 11 13 15 17]
slice2 := slice1[2:4]
fmt.Println(slice2) // [13 15]
}
make()関数でスライスを作成する
Goにはmake()という関数があり、これを使ってスライスを作成することもできます。これはスライスの種類、長さ、そしてそのスライスの容量を引数に受け取ります。
package main
import "fmt"
func main() {
sampleSlice := make([]int, 6) // 要素数が6の数値のスライスを作成
fmt.Println(sampleSlice) // [0 0 0 0 0 0]
}
len()関数とcap()関数
len()関数とcap()関数は、スライスの長さと容量を提供します。
両者の違いを理解するために、例を見てみましょう。
package main
import "fmt"
func main() {
sampleSlice := []int{2, 4, 6, 8, 10}
fmt.Println(len(sampleSlice), cap(sampleSlice)) // 5 5
arr := [6]int{1, 2, 3, 4, 5, 6}
arrSlice := arr[1:4]
fmt.Println(arrSlice) // [2 3 4]
fmt.Println(len(arrSlice), cap(arrSlice)) // 3 4
}
スライスのゼロ値
スライスのゼロ値はnilです。つまり、そのスライスのlengthはゼロになります。
package main
import "fmt"
func main() {
sampleSlice := []int{}
fmt.Println(len(sampleSlice), cap(sampleSlice)) // 0 0
}
スライス内の値を変更する
スライス内の値の変更は実に簡単です。
スライスに対してインデックスを指定してデータを割り当てるだけです。
package main
import "fmt"
func main() {
sampleSlice := []int{1, 2, 3, 4}
sampleSlice[1] = 0
fmt.Println(sampleSlice) // [1 0 3 4]
}
スライスから値を削除する
スライス内のインデックスiの値を削除するには、インデックスiまでとi+1から末尾までの要素を単純に追加すればよいです。
package main
import "fmt"
func main() {
sampleSlice := []int{1, 2, 3, 4, 5, 6, 7, 8}
_ = append(sampleSlice[:3], sampleSlice[4:]...) // 三番目の要素を削除する
fmt.Println(sampleSlice) // [1 2 3 5 6 7 8 8]
}
スライスを関数に渡す方法
スライスを関数に渡し、その内部で変更を加えた場合、その変更は外部でも利用できるようになります。この背景には、スライスが参照型であることがあります。
package main
import "fmt"
func main() {
sampleSlice := []int{1, 2, 3, 4, 5}
PrintSlice(sampleSlice) // [1 2 3 4 5]
}
func PrintSlice(slice []int) {
fmt.Println(slice)
}
スライスの関数
スライスをさらに使いやすくするスライス関数があります。ここでは重要なものをいくつか紹介します。
package main
import "fmt"
func main() {
s := []int{1, 2, 3, 4, 5}
var s2 = make([]int, 5)
s = append(s, 6, 7)
fmt.Println(s) // [1 2 3 4 5 6 7]
// 関数をコピー
e := copy(s2, s)
fmt.Println(s2, e) // [1 2 3 4 5] 5
}
スライスのスライス
本質的に多次元的なスライスを作成することができます。
package main
import "fmt"
func main() {
numbers := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}, // カンマを忘れずに
}
fmt.Println(numbers) // [[1 2 3] [4 5 6] [7 8 9]]
}
スライスの要素に対する繰り返し処理
スライスに対する反復処理は、for-rangeループを使用して行うことができます。単純なforループをlen関数と一緒に使うこともできます。以下はその方法である。
package main
import "fmt"
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7}
for i, v := range numbers {
fmt.Println(i, v)
}
}
// 出力結果:
// 0 1
// 1 2
// 2 3
// 3 4
// 4 5
// 5 6
// 6 7