TL;DR
よくある間違い
例えば、
[][]int[
[]int[11 12 13 14 15]
[]int[21 22 23 24 25]
[]int[31 32 33 34 35]
[]int[41 42 43 44 45]
[]int[51 52 53 54 55]
]
から
[][]int{
[]int[23 24]
[]int[33 34]
[]int[43 44]
]
↑この参照がほしい
arr[1:4][2:4]
ってやると、
var arr = [][]int{
[]int{11, 12, 13, 14, 15},
[]int{21, 22, 23, 24, 25},
[]int{31, 32, 33, 34, 35},
[]int{41, 42, 43, 44, 45},
[]int{51, 52, 53, 54, 55},
}
sliced := arr[1:4][2:4]
for _, row := range sliced {
fmt.Println(row)
}
// 結果
// [41 42 43 44 45]
// [51 52 53 54 55]
となってしまう。これは(arr[1:4])[2:4]
と同義
arr[1:4]
0:[21 22 23 24 25]
1:[31 32 33 34 35]
2:[41 42 43 44 45]
から[2:4を]スライス
[41 42 43 44 45]
[51 52 53 54 55] (参照元のメモリには残ってる)
正解例
内部の配列のみ通常のスライス。
var arr = [][]int{
[]int{11, 12, 13, 14, 15},
[]int{21, 22, 23, 24, 25},
[]int{31, 32, 33, 34, 35},
[]int{41, 42, 43, 44, 45},
[]int{51, 52, 53, 54, 55},
}
// slice範囲
rf, rt, cf, ct := 1, 4, 2, 4
// slicing
sliced := make([][]int, rt-rf)
copy(sliced, arr[rf:rt]) // arr[rf:rt]のスライスを書き換えちゃうと、元の配列で内部配列のlengthが変わっちゃう
for i := range sliced {
sliced[i] = sliced[i][cf:ct]
}
// show
fmt.Println("Source array")
for _, row := range arr {
fmt.Println(row)
}
fmt.Println("\nSliced array 1:4,2:4")
for _, row := range sliced {
fmt.Println(row)
}
// [23 24]
// [33 34]
// [43 44]
当然要素のメモリ参照は元の配列と同じなので、sliced
を書き換えるとarr
も書き換わる。