var arr [3]string
var arr [3][3]string
arr[1] = "text"
fmt.Print(arr[2])
arr := [3]string{"青", "黄", "赤"}
or
arr := [...]string{"青", "黄", "赤",} // 要素数をコンパイラが計算する。最後にカンマが必須
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
or
func main() {
arr := [3]string{"青", "黄", "赤",}
for i, item := range arr {
fmt.Println(i, item)
}
}
rangeを使った書き方で、配列のインデックスや要素が不要な場合は_と置くことでコンパイラにunusedエラーを吐かせないようにすることができる
arr1 := [3]string{"青", "黄", "赤",}
arr2 := arr1
arr1[0] = "緑"
fmt.Println(arr1) // [緑 黄 赤]
fmt.Println(arr2) // [青 黄 赤]
arr[始端(含む):終端(含まない)]で配列を切り出す
arr := [...]string{
"a", // 0
"b", // 1
"c", // 2
"d", // 3
"e", // 4
}
fmt.Println(arr[1:4]) // [b c d]
fmt.Println(arr[:3]) // [a b c]
fmt.Println(arr[3:]) // [d e]
fmt.Println(arr[:]) // [a b c d e]
slice := []string{"a", "b", "c",}
スライスと配列は一見似ているが厳密には違うものと考えて良さそう
func main() {
arr := [...]string{"a", "b", "c",}
slice := arr[:]
fmt.Printf("%T\n",arr) // [3]string
fmt.Printf("%T\n",slice) // []string
}
配列は宣言時にサイズが指定されているが、スライスは指定しない
また、代入や関数の引数に渡した先で中身を書き換えると元のスライス/配列も書き換わるという点で配列と異なる
ポインタのセクションを参照
slice1 := []string{"青", "黄", "赤",}
slice2 := slice1
slice1[0] = "緑"
fmt.Println(slice1) // [緑 黄 赤]
fmt.Println(slice2) // [緑 黄 赤]
Goは基本的に値渡しを行うので2つの変数を調べてもアドレスは異なるが、参照先は同じであるためこのようになる。
参考:https://christina04.hatenablog.com/entry/2017/09/26/190000
配列を使うとサイズが大きい場合に大量のコピーが走るので基本的に配列よりもスライスを使うべきかも
slice := []string{"青", "黄", "赤"}
slice = append(slice, "虹色")
fmt.Println(slice)
スライスが持つことができる要素数(容量)はcapで確認できる
appendを行うと、 元スライスの倍の容量を原則確保する
倍にしても必要量確保できない場合は必要量を確保する
func dump(slice []string) {
fmt.Printf("長さ %v, 容量 %v %v\n", len(slice), cap(slice), slice)
}
func main() {
slice := []string{"a", "b"}
dump(slice) // 長さ 2, 容量 2 [a b]
dump(slice[:1]) // 長さ 1, 容量 2 [a]
slice = append(slice, "c")
dump(slice) // 長さ 3, 容量 4 [a b c]
slice = append(slice, "d", "e", "f", "g", "h", "i")
dump(slice) // 長さ 9, 容量 9 [a b c d e f g h i]
}
また、appendを行った行った場合は新しいスライスが作られる
func main() {
slice1 := []string{"a", "b"}
slice2 := append(slice1, "c")
slice1[0] = "x"
slice2[1] = "y"
fmt.Println(slice1) // [x b]
fmt.Println(slice2) // [a y c]
}
appendを大量に行うのは遅くなるので避けたほうが無難
3個目のインデックス指定でスライスの容量を制限できる
スライスのサイズを容量よりも大きく指定するとエラーになる
slice := []string{"a", "b", "c", "d", "e"}[0:4:4]
// 長さ 4, 容量 4 [a b c d]
fmt.Printf("長さ %v, 容量 %v %v\n", len(slice), cap(slice), slice)
append時にスライスの容量が不足すると新しい配列を割り当ててコピーする比較的重い処理が走る
なので、なるべく十分な容量のスライスを事前に確保しておくことができる
slice := make([]string, 0, 10) // 長さが0、容量が10のスライス
func echo(text ...string) {
for _, item := range text {
fmt.Println(item)
}
}
Goではキーの型も指定する
配列同様に最後の要素にもカンマが必要
stock := map[string]int{
"apple": 8,
"orange": 16,
"grape": 10,
}
存在しないキーを参照した場合は、int型なら0を返すなどエラーにならない
存在するキーかどうかを判別するには代入時に2つの値を用意する
stock := map[string]int{
"apple": 8,
"orange": 16,
"grape": 10,
}
fmt.Println(stock["banana"]) // 0
banana, ok := stock["banana"] // ここではokとしているが名前は任意
fmt.Println(banana, ok) // 0 false
if文と組み合わせて、以下のような書き方もできる
if apple, ok := stock["apple"]; ok {
fmt.Printf("りんごの在庫は%v個", apple) // りんごの在庫は8個
} else {
fmt.Println("りんごの在庫はありません") // 実行されない
}
スライスと同様にmakeで
stock := make(map[string]int, 8)
Goはセット(要素が重複しないコレクション)を提供していないが、マップで代用できる
ブール値を使って重複要素を消す例
signal := []string{"blue", "yellow", "green", "blue"}
set := make(map[string]bool)
for _, v := range signal {
set[v] = true // 重複要素を取り除く
}
// スライスに戻す処理
setSlice := make([]string, 0, len(set))
for i, _ := range set {
setSlice = append(setSlice, i)
}
fmt.Println(setSlice) // [blue yellow green]