Open4

Golang の基本構文カンペ集

hassaku63hassaku63

当面メインで利用する予定なし && 普段が Python たまに JavaScript なのですぐに構文忘れそう

ということですぐ思い出せるようにメモしておく

hassaku63hassaku63

Slice

Slice tricks で。insert, filter などはここで
https://ueokande.github.io/go-slice-tricks/

full slice expression という書き方があり、コロン2つが使える

x := []int{1,2,3,4,5}

fmt.Println(x[1:3:3])  // start:end:max

range

Python では enumerate や dict.items あたりの使用感に近い

x := []int{3,4,5}

for i, v := range x {
  fmt.Println(i, v)
}

Map

用途の異なる初期化方法が3つあるらしい

// 空
x1 := map[string]int{}

// make
x2 := make(map[string]int)

// make で初期化し、予め容量を確保しておく
x2 := make(map[string]int, 10)

キーの存在確認は多値で確認できる

m := map[string]int{
	"alice": 42,
	"bob":   33,
}
age, key_exists := m["carol"]
fmt.Println(age, key_exists)  // 0, false

ゼロ値だとキーの追加はできない (panic)

var x map[string]int

x["alice"] = 1  // panic: assignment to entry in nil map

ゼロ値の map は nil になる。長さも取得できる

var x map[string]int
fmt.Println(x == nil) // true
fmt.Println(len(x)) // 0
hassaku63hassaku63

構造体とフィールドの export

「構造体は export しないけどフィールドは export する」のユースケースについて。

一例が "encoding/json"

構造体で定義したフィールドを JSON のキーとして encode するかどうかは、フィールドの export 有無でコントロール可能。構造体そのものを export していなくとも、JSON のシリアライズ/デシリアライズのフィールド単位のコントロールを行う場合にフィールドを export しない選択肢が生じる

hassaku63hassaku63

メソッド

レシーバに持ってくる型を、型にするのかポインタにするのか問題。

参考資料はこちら↓
https://skatsuta.github.io/2015/12/29/value-receiver-pointer-receiver/

構造体に対するレシーバを作りたい場合に、構造体型なのかそのポインタなのかでは別物。

レシーバは関数の第0引数であり、値渡しの場合は引数の値コピーを、ポインタの場合はポインタ渡しを行っている。

なので、大きな構造を値コピーするのは非効率であるし、「オブジェクト内部の状態書き換え」のような文脈で利用するなら必然的に値コピーでなくポインタ渡しを選ぶ必要が出る。

また、ポインタ渡しの場合はフィールドの nil チェックをすべきとある。これは、ゼロ値 (=nil) の構造体変数からでもポインタ渡しのメソッドは呼び出し可能だから。なので、レシーバ自身の nil チェックがあると安全。

概念としてはレシーバは this や self に相当するものとして理解できるが、あくまでも「第0引数」であることを念頭に置くことで nil の可能性を考慮すべき、ということを思い出せる、はず。

値でレシーバを作る意味があるケースは、以下

  • 値コピーのコストが低い(プリミティブベースの型や、小さな構造体)
  • もともと参照型ベースなもの(map, chan とか)
  • immutable な型を扱う場合