配列 / スライス
| 対応: | Go 1.0(2012) |
|---|
配列は固定長のデータ列で、スライスは可変長のデータ列です。Goでは柔軟性の高いスライスが日常的に使われます。
構文
// 配列の宣言(固定長)
var arr [3]int
arr := [3]int{10, 20, 30}
arr := [...]int{10, 20, 30} // 要素数を自動カウント
// スライスの宣言(可変長)
var s []int
s := []int{10, 20, 30}
s := make([]int, 長さ) // ゼロ値で初期化
s := make([]int, 長さ, 容量) // 長さと容量を指定
// スライス操作
s = append(s, 値) // 末尾に要素を追加
s = append(s, 他スライス...) // スライスを結合
dst := make([]int, len(src))
copy(dst, src) // コピー
s2 := s[開始:終了] // 部分スライス
構文一覧
| 関数/操作 | 概要 |
|---|---|
| append(s, v...) | スライスに要素を追加します。容量が足りない場合は自動で拡張されます。 |
| copy(dst, src) | srcからdstへ要素をコピーします。コピーされた要素数を返します。 |
| len(s) | スライス(または配列)の現在の要素数を返します。 |
| cap(s) | スライスの容量(再割り当てなしに保持できる最大要素数)を返します。 |
| make([]T, len, cap) | 指定した型・長さ・容量のスライスを作成します。 |
| s[i:j] | インデックスiからj-1までの部分スライスを作成します。元スライスのメモリを共有します。 |
サンプルコード
sample_array_slice.go
package main
import "fmt"
func main() {
// 配列(固定長)
arr := [3]string{"Son Goku", "Vegeta", "Krillin"}
fmt.Println(arr[0], len(arr)) // Son Goku 3
// スライス(可変長)
fighters := []string{"Son Goku", "Vegeta"}
fmt.Printf("len=%d cap=%d\n", len(fighters), cap(fighters))
// append で要素を追加
fighters = append(fighters, "Krillin", "Piccolo")
fmt.Println(fighters)
// スライスのコピー(独立したメモリ)
copied := make([]string, len(fighters))
copy(copied, fighters)
copied[0] = "Bulma"
fmt.Println(fighters[0]) // Son Goku(影響なし)
fmt.Println(copied[0]) // Bulma
// 部分スライス
part := fighters[1:3]
fmt.Println(part) // [Vegeta Krillin]
// makeで事前に容量を確保(パフォーマンス改善)
nums := make([]int, 0, 10)
for i := 0; i < 5; i++ {
nums = append(nums, i*2)
}
fmt.Println(nums)
}
go run array_slice.go Son Goku 3 len=2 cap=2 [Son Goku Vegeta Krillin Piccolo] Son Goku Bulma [Vegeta Krillin] [0 2 4 6 8]
概要
配列とスライスの大きな違いは長さが型の一部かどうかです。『[3]int』と『[4]int』は別の型ですが、スライスは長さに関係なく同じ型です。実用上はほぼスライスを使います。
部分スライス(『s[1:3]』など)は元のスライスのメモリを共有します。部分スライスへの変更は元スライスにも影響するため、独立したコピーが必要な場合は必ず『copy()』を使ってください。
大量の要素を追加することが事前にわかっている場合は、『make([]T, 0, 容量)』で容量を予約しておくと、都度メモリを再割り当てするコストが抑えられてパフォーマンスが向上します。マップと同様に、スライスも参照型である点に注意してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。