[学習メモ]A Tour of Go[More types: slices, maps.]
ArrayとSliceついて学習します。
Slices
可変長な配列というイメージ。
配列より一般的に使用される
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13}
//↓slice []の中に長さを指定していない
var s []int = primes[1:4]
fmt.Println(s)
}
Slices are like references to arrays
引用
スライスは配列への参照のようなものです。
スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示しています。
スライスの要素を変更すると、その元となる配列の対応する要素が変更されます。
同じ元となる配列を共有している他のスライスは、それらの変更が反映されます。
つまりSliceはポインタ型の集まり?
下のリンクのようにややこしい状況もあるそうです
[Try Golang! Sliceってポインタなの?それともポインタじゃないの?]
https://medium.com/veltra-engineering/is-the-golang-slice-a-pointer-or-not-a-pointer-99433f2cea17
Slice literals
スライスのリテラルは長さのない配列リテラルのようなものです。
そもそも配列リテラルってなに?
https://jsprimer.net/basic/data-type/#array
package main
import "fmt"
func main() {
q := []int{2, 3, 5, 7, 11, 13}
fmt.Println(q)
r := []bool{true, false, true, true, false, true}
fmt.Println(r)
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
fmt.Println(s)
}
Slice defaults
スライスするときに上限と下限を決めることができる
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
s = s[1:4]
fmt.Println(s)
s = s[:2]
fmt.Println(s)
s = s[1:]
fmt.Println(s)
}
Slice length and capacity
スライスは長さ( length )と容量( capacity )の両方を持っています。
スライス s の長さと容量は len(s) と cap(s) という式を使用して得ることができます。
Nil slices
スライスのゼロ値はnil
Creating a slice with make
make関数はゼロ化された配列を示すスライスを返す。
a := make([]int, 5) // len(a)=5
//a len=5 cap=5 [0 0 0 0 0]
Slices of slices
スライスは、他のスライスを含む任意の型を含むことができます。
package main
import (
"fmt"
"strings"
)
func main() {
// Create a tic-tac-toe board.(三目並べ)
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// The players take turns.
board[0][0] = "X"
board[2][2] = "O"
board[1][2] = "X"
board[1][0] = "O"
board[0][2] = "X"
for i := 0; i < len(board); i++ {
fmt.Printf("%s\n", strings.Join(board[i], " "))
}
}
多次元配列のような認識です。
Appending to a slice
スライスへ新しい要素を追加するには、Goの組み込みの append を使います。 append についての詳細は documentation を参照してみてください。
func append(s []T, vs ...T) []T
Range
for ループに利用する range は、スライスや、マップ( map )をひとつずつ反復処理するために使います。
スライスをrangeで繰り返す場合、rangeは反復毎に2つの変数を返します。 1つ目の変数はインデックス( index )で、2つ目はインデックスの場所の要素のコピーです。
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
[output]
2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128
phpで言うところのforeachでしょうか
Range continued
インデックスや値は、 " _ "(アンダーバー) へ代入することで捨てることができます。
package main
import "fmt"
func main() {
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i) // == 2**i
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}
sliceだけで結構たくさん学ぶことがありますね。
Maps
mapはキーと値を関連付ける。ゼロ値はnil
make関数でマップを初期する。
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
Map literals
structとは違い、キーが必要になる。
Map literals continued
もし、mapに渡すトップレベルの型が単純な型名である場合は、リテラルの要素から推定できますので、その型名を省略することができます。
↑あまりよくわかってないです。。。正直
Mutating Maps
mapの操作
m へ要素(elem)の挿入や更新:
m[key] = elem
要素の取得:
elem = m[key]
要素の削除:
delete(m, key)
キーに対する要素が存在するかどうかは、2つの目の値で確認します:
elem, ok = m[key]
もし、 m に key があれば、変数 ok は true となり、存在しなければ、 ok は false となります。
なお、mapに key が存在しない場合、 elem はmapの要素の型のゼロ値となります。
存在確認でいちいち上のやり方をしないといけないのでしょうか?
PHPでいうところのarray_key_existsや、issetのような関数があれば良いのですが・・・
Function values
関数も変数として扱う。
Function closures
クロージャについて少し復習しないとなと感じました。(あまり理解ができていない・・・)
この記事が気に入ったらサポートをしてみませんか?