見出し画像

[学習メモ]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

クロージャについて少し復習しないとなと感じました。(あまり理解ができていない・・・)





この記事が気に入ったらサポートをしてみませんか?