初めに
Goの配列とSliceに関してのアウトプットを行う。
配列
Goの配列は固定長であり長さを変更することができない。
宣言
配列は以下のように宣言する。
[要素数]型
// 例
var i [2]int
宣言した段階では、ゼロ値が格納されている。
func main() {
var s [2]string
fmt.Println(s)
var i [2]int
fmt.Println(i)
}
// 出力結果
[ ]
[0 0]
要素に値を格納
インデックス番号を指定して値を格納する方法は以下である。
func main() {
var s [2]string
s[0] = "Go"
s[1] = "Study"
fmt.Println(s)
fmt.Println(s[0])
}
// 出力結果
[Go Study]
Go
宣言と同時に値を格納する場合は以下である。
func main() {
s := [2]string{"Go", "Study"}
fmt.Println(s)
// varを使用する
var ss = [2]string{"ss", "ss"}
fmt.Println(ss)
i := [5]int{1, 2, 3, 4, 5}
fmt.Println(i)
}
// 出力結果
[Go Study]
[ss ss]
[1 2 3 4 5]
多次元配列
基本形
// 宣言
var 配列名 [要素数][要素の中の要素数]型
// 宣言と初期化
var 配列名 = [要素数][要素の中の要素数]型{{要素},{要素}}
例
宣言された段階では、ゼロ値が格納されている。
func main() {
// 宣言のみ初期化なし
var arr [3][2]int
fmt.Println(arr)
// string型の宣言と同時に初期化
s := [3][2]string{{"e0.0", "e0.1"}, {"e1.0", "e1.1"}, {"e2.0", "e2.1"}}
fmt.Println(s)
// int型の宣言と同時に初期化
i := [2][1]int{{2}, {3}}
fmt.Println(i)
}
// 出力結果
[[0 0] [0 0] [0 0]]
[[e0.0 e0.1] [e1.0 e1.1] [e2.0 e2.1]]
[[2] [3]]
要素の取得と変更
通常の配列
func main() {
arr := [2]string{"Go", "Study"}
// インデックス番号0と1の要素を出力
fmt.Println(arr[0], arr[1])
// インデックス番号1の要素を変更
arr[1] = "Use"
// インデックス番号0と1の要素を再度出力
fmt.Println(arr[0], arr[1])
}
// 出力結果
Go Study
Go Use
多次元配列
func main() {
multi_arr := [3][2]string{{"e0.0", "e0.1"}, {"e1.0", "e1.1"}, {"e2.0", "e2.1"}}
// インデックス番号0の要素の0番目の要素とインデックス番号2の1番目の要素を出力
fmt.Println(multi_arr[0][0], multi_arr[2][1])
// 先ほど出力した要素を変更
multi_arr[0][0] = "e0.0change"
multi_arr[2][1] = "e2.1change"
// インデックス番号0の要素の0番目の要素とインデックス番号2の1番目の要素を再度出力
fmt.Println(multi_arr[0][0], multi_arr[2][1])
}
// 出力結果
e0.0 e2.1
e0.0change e2.1change
要素数の省略
要素数は以下のように省略して記載することも可能である、
func main() {
s := [...]string{"Go", "Study"}
fmt.Println(s)
fmt.Println("要素数", len(s))
i := [...]int{1, 2, 3, 4, 5}
fmt.Println(i)
fmt.Println("要素数", len(i))
}
// 出力結果
[Go Study]
要素数 2
[1 2 3 4 5]
要素数 5
しかし、宣言時に省略することはできないので、初期化と同時に使用する必要がある。
func main() {
var s [...]string
fmt.Println(s)
var i [...]int
fmt.Println(i)
}
// 出力結果
invalid use of [...] array (outside a composite literal)
invalid use of [...] array (outside a composite literal)
また、配列は固定長なので初期化時の要素数を超えた要素数を格納しようとするとエラーになる。
func main() {
i := [2]int{1, 1}
s := [...]string{"Go", "Study"}
i[3] = 2
s[2] = "エラーです"
fmt.Println(s)
fmt.Println(i)
}
// 出力結果
invalid argument: index 3 out of bounds [0:2]
invalid argument: index 2 out of bounds [0:2]
Slice
Sliceは可変長である。
配列の要素の初期値はゼロ値であったが、Sliceのゼロ値はnilが格納される。
宣言
初期化を伴わない場合
基本形
var 変数名 []型
例
var i []int
宣言時の配列との違い
配列・・・[要素数]
もしくは[...]
を使用する。
Slice・・・[]
もしくはmake
関数を使用する。
宣言時に初期化する場合
基本形
var 変数名 = []型{格納したい要素の値}
例
func main() {
var i = []int{1, 2}
fmt.Println(i)
}
// 出力結果
[1 2]
宣言時に配列を使用する場合
基本形
var 変数名 = 配列[low : high]
例
func main() {
var arr [2]int
var i = arr[0:2]
fmt.Println(i)
}
// 出力結果
[0 0]
low high
宣言時に初期化する場合には4つの定義方法がある。
- low highの両方を指定
- lowのみ指定
- highのみ指定
- 指定なし
low・・・指定した値 = インデックス番号
high・・・(指定した値 - 0) = インデックス番号
low highの両方を指定
[low:high]
のような指定の方法になる。
インデックス番号 low ~ (high - 1)の配列を取得する。
[0:3]
のような指定方法だと、インデックス番号 0 ~ 2の配列を取得する。
func main() {
arr := [...]int{1, 2, 3}
// インデックス番号 0 ~ 1 の配列を取得
slice1 := arr[0:2]
// インデックス番号 1 の配列を取得
slice2 := arr[1:2]
fmt.Println(arr)
fmt.Println(slice1)
fmt.Println(slice2)
// 出力結果
[1 2 3]
[1 2]
[2]
}
上記のような結果になる。
また、宣言に使用した配列には変更はない。
使用することはないと思うが、low highが同じ値の場合はSliceはエラーにならず生成されるが、要素は格納されていない。
func main() {
arr := [...]int{1, 2, 3}
slice := arr[1:1]
fmt.Println(slice)
fmt.Println(len(slice))
}
// 出力結果
[]
0
異常系
lowがhighより大きいなどの不正な定義をするとエラーになる。
func main() {
arr := [...]int{1, 2, 3}
slice1 := arr[2:1]
slice2 := arr[2:5]
fmt.Println(slice1)
fmt.Println(slice2)
}
lowのみ指定
lowのみ指定すると指定したインデックス番号から最後尾までのSliceを生成する。
例
配列[low:]
func main() {
arr := [...]int{1, 2, 3}
slice1 := arr[0:]
slice2 := arr[2:]
fmt.Println(slice1)
fmt.Println(slice2)
}
// 出力結果
[1 2 3]
[3]
hegtのみ指定
hegtのみ指定すると配列の要素の先頭から hegt - 1 までを取得してSliceを生成する。
例
配列[:hegt]
func main() {
arr := [...]int{1, 2, 3}
// 先頭からインデックス番号2まで
slice1 := arr[:3]
slice2 := arr[:2]
slice3 := arr[:0]
fmt.Println(slice1)
fmt.Println(slice2)
fmt.Println(slice3)
}
// 出力結果
[1 2 3]
[1 2]
[]
low hegtの指定なし
指定なしの場合は、配列の先頭から最後尾までの要素を取得してSliceをして生成する。
例
配列[:]
func main() {
arr := [...]int{1, 2, 3}
slice1 := arr[:]
fmt.Println(slice1)
}
// 出力結果
[1 2 3]
要素の追加
Sliceは可変長であるため、要素の追加が可能である。
appendを使用して要素を追加することができる。
例
append[対象のSlice, 追加したい要素]
func main() {
// Sliceを宣言
slice := []int{1, 2, 3}
slice1 := append(slice, 4)
fmt.Println(slice)
fmt.Println(slice1)
// 配列を使用してSliceを生成
var arr [3]int
slice2 := arr[:]
slice3 := append(slice2, 1, 2)
fmt.Println(slice3)
fmt.Println(arr)
}
// 出力結果
[1 2 3]
[1 2 3 4]
[0 0 0 1 2]
[0 0 0]
配列を使用して宣言した場合に、appendを使用しても、元の配列の値は変更されていないことが分かる。
SliceにSliceを追加する
SliceにSliceを追加することも可能である。
追加する場合は以下の様に記載する。
append(元になるSlice, 追加したいSlice...)
追加したいSliceに...
がないとエラーになるので注意が必要である。
func main() {
var silce1 = []int{1, 2, 3}
var slice2 = []int{4, 5, 6}
result := append(silce1, slice2...)
fmt.Println(result)
}
// 出力結果
[1 2 3 4 5 6]
上記と同様の方法で配列を追加しようとするとエラーになる。
func main() {
var silce1 = []int{1, 2, 3}
var slice2 = [3]int{4, 5, 6}
result := append(silce1, slice2...)
fmt.Println(result)
}
cannot use slice2 (variable of type [3]int) as type []int in argument to append
要素の変更
配列を使用しないで宣言をした場合
配列と同じように、インデックス番号を指定して代入すれば要素が変更される。
func main() {
var i = []int{1, 2}
// インデックス番号0の要素を5に変更
i[0] = 5
fmt.Println(i)
}
// 出力結果
[5 2]
配列を使用して宣言をした場合
配列を使用して宣言した場合に、スライスを変更すると元の配列の要素が変更される。
要素を追加する際には、元の配列の要素に変更はなかったため、変更があった場合に配列の要素が変更される。
func main() {
var arr [2]int
fmt.Println(arr)
var i = arr[:]
i[0] = 5
fmt.Println(arr)
}
// 出力結果
[0 0]
[5 0]
appendを使用して生成された変数
配列を使用して宣言したSliceにappendを使用する。
func main() {
// 配列生成
var arr [2]int
fmt.Println(arr)
// 先ほどの配列を使用してSliceを生成
var i = arr[:]
// Sliceに要素を追加
var ii = append(i, 3)
// 配列を使用したSliceの要素を変更
i[0] = 1
// 配列を使用したSliceにappendを使用したSliceの要素を変更
ii[1] = 2
fmt.Println(arr)
fmt.Println(ii)
}
上記の場合、変数i
とii
は別の変数である。
よって、i
の要素を変更すると元の配列の値が変更されるが、ii
を変更しても元の配列の値は変更されない。
要素の削除
先頭の要素の削除
先頭の要素を削除して再代入している。
func main() {
var slice1 = []int{1, 2, 3, 4, 5, 6}
slice1 = slice1[1:]
fmt.Println(slice1)
}
// 出力結果
[2 3 4 5 6]
最後尾の要素を削除
最後尾の要素を削除して再代入している。
func main() {
var slice1 = []int{1, 2, 3, 4, 5, 6}
slice1 = slice1[:len(slice1) - 1]
fmt.Println(slice1)
}
// 出力結果
[1 2 3 4 5]
Range
for文と一緒に使用し、Sliceやmapを反復処理する。
例
iにはインデックス番号、vにはインデックス番号にある要素が格納される。
for i, v := range Slice {
// 処理
}
var pow = []int{1, 2, 4}
func main() {
for i, v := range pow {
fmt.Println(i)
fmt.Println(v)
fmt.Println("-----")
}
}
// 出力結果
0
1
-----
1
2
-----
2
4
-----
要素の省略
要素が不要の場合は式に省略することができる。
var pow = []int{1, 2, 4}
func main() {
for i := range pow {
fmt.Println(i)
}
}
// 出力結果
0
1
2
lengthとcapacity
Sliceにはlengthとcapacityが存在する。
lengthは要素数で、capacityは元となる配列(もしくはSlice)の要素数である。
通常のSliceの場合
func main() {
// 要素が5つのSliceを生成
var i = []int{0, 1, 2, 3, 4}
// 変数iの要素数0~2を代入
c := i[:3]
fmt.Println(i)
fmt.Println(c)
fmt.Println("original length =", len(i), "\nchange length = ", len(c), "\nchange_capacity = ", cap(c))
}
// 出力結果
[0 1 2 3 4]
[0 1 2]
original length = 5
change length = 3
change_capacity = 5
配列を使用したSliceの場合
func main() {
// 要素が5つの配列を宣言
var arr = [5]int{0, 1, 2, 3, 4}
// arr変数の要素数0~2を代入
i := arr[:3]
fmt.Println(arr)
fmt.Println(i)
fmt.Println("array length =", len(arr), "\nslice_length = ", len(i), "\nslice_capacity = ", cap(i))
}
// 出力結果
[0 1 2 3 4]
[0 1 2]
array length = 5
slice_length = 3
slice_capacity = 5
make関数
make関数を使用することで、lengthとcapacityを指定してSliceを作成することができる。
基本形
make([]型, [length指定], [capacity指定])
例
capacityは指定していないとlengthと同じ数値となる。
func main() {
// lenthのみを3で指定
one := make([]int, 3)
fmt.Println(one, len(one), cap(one))
// lenthを4、capacityを5で指定
two := make([]int, 4, 5)
fmt.Println(two, len(two), cap(two))
}
// 出力結果
[0 0 0] 3 3
[0 0 0 0] 4 5
lengthがcapacityを超えた数値で指定するとエラーになる。
func main() {
one := make([]int, 3, 1)
}
// 出力結果
invalid argument: length and capacity swapped