golangメモ

golang 書いてて、設計上判断迷うときのためのメモ。随時更新か投稿し直すので、コメントがあれば twitter でください。

（他の言語同様）導入が簡単かどうかは採用ポイントの一つになる。バージョン周回遅れの gcc を使うしか手がない MIPS が、最大の弱点。

pointer : 使うかどうかの判断ポイントは、「変更する対象かどうか」を第一に考える。速度とか気になっちゃうけど、そういうのは後回し。64 bit 環境だとポインタも 8 byte というバカにできない大きさだったりするし、そもそも内部的な処理系はそういうナイーブな実装ではない。値渡しのほうが並列処理するときに安全になりやすい。値渡しを優先。

struct : 初期化手順はデフォルトの仕組みを活用するとよい。makeStructA(param1, param2) と書くのと A{param1, param2} と書くのと大差ない。一般的に、後者のほうがコード量は減り、安全になりやすい。

interface : 使わないに越したことは無い。しかしgolang は結局型システムの鬼みたいなものなので、効果的に使えるのであれば、必要以上に躊躇することもない。

[]byte : nilは空。nilで安全に扱えて、nil に append できる。slice は値で、大きさを変更したら代入する。deep コピーを取りたい場合は、nil に append するのが一番簡単。

```
a := []byte{ 1,2,3 }
b := append([]byte(nil), a...)
c := append([]byte{}, a...) // こっちのほうが短いけどね
```

map : nilは空だが、nil で要素にアクセスすると panic する。読むのはいいけど、書くのはダメ。普通は書くので、忘れやすいけど、初期化必須。値を入れても map 自体は変わらない。

chan : 使い終わったら「書き込み側から」「必ず close」する。close は自動的には行われない。つまり make と対応させて close させるべし。close を 2 回やると panic する。close 後は chan のフィールドを nil で潰しておくと 2 重 close は起こしにくい。fan-out には使えるけれども、fan-in には基本的には使ってはいけない。例外はプロセス終了時まで close されない chan である時や、close できる条件が別の方法で得られる時（要素数が分かっているとか）。得てして fan-in 的なものの実装には mutex + 関数の形がシンプルになる。速度面でも mutex + 関数のほうが普通は速い。chan は結果待ちをするときや select と組み合わせるときに使うべし。

string : []byte の immutable 版。print するときに、文字列的に出力される。

[]byte か map かの判断ポイントは、バランスで決める。key を使った参照が多いかどうか。struct の中に使うときは、その struct の初期化を楽にしたいかどうか（mapへの代入には初期化必須）。struct の中にあるときは、struct のメソッドレシーバをポインタにしないといけないかどうかが、どちらを選ぶかによって変わることに注意。map であればポインタでなくて良い。struct を frozen にしたい場合は、[]byte にすべし。map 自体をコピーすると、どこで変更されるかわかったもんじゃない。

makeで同じように作るけれども、何かを追加する操作に関しては（普通は何かを追加するので）、map, chan は pointer 的に振舞うことに注意する。slice は値的に振舞う。

メソッドレシーバには self を使う。

```
func (self A) DoSome() error {
	return nil
}
```

byteorder : big-endian, little-endian と分かっている場合は、encoding/binary でやる。singed は unsiged にキャストする。native であるという場合は、unsafe を駆使する。unsafeなので、[]byteから戻すときは長さをチェックすべき。しばらく離れるとすぐに忘れてしまうけれど、こんな感じ：

```
package main

import (
	"log"
	"unsafe"
)

type A struct {
	V int32
}

func main() {
	buf := []byte{0,0,0,0,0,0,0,0x7f}
	var i int32
	if len(buf) >= unsafe.Sizeof(i) {
		i = *(*int32)(unsafe.Pointer(&buf[0]))
	}

	copy(buf, (*[unsafe.Sizeof(A{})]byte)(unsafe.Pointer(&A{2}))[:])

	log.Print(i, buf)
}
```

可変長バイト列を持つ構造データを定義するときは []byte を base type にすると簡単。フィールドにアクセスするメソッドを用意しておく。固定長バイト列データは struct にしておくと、割り当てたときに自動的にサイズが決まって扱いやすい。

```
type VarA []byte

func (self VarA) Iter() []VarA {
	return nil
}

type FixedA struct{}
```

シリアライズする場合 encoding.BinaryMarshaler が目につくけれども、例えば `VarA` は単にキャストして連結すれば良いし、他にも実は io.Reader のインターフェースでバイト列書き込みを実装するという手がある。オブジェクトからバイト列を「読み出す」という意味。

conversionとcgo
--------
`unsafe.Sizeof` は `C.sizeof` ではない。linux_amd64 な環境だと `unsafe.Sizeof(int(0))` は 8 だが、`C.sizeof(int)` は 4 になる。幅の固定されていない `int` を使って先ほどの変換を行ってはいけない。やむなく `int` が入ってくる場合は、*かならず* `cgo` の世話になること。

このようなC構造体があったとして、golang 側からバイト列として取り出せたとする。たとえば native file format として保存されたものを読み出す場合など。

```c
// C part
struct a {
	int X
}
```

次のパターンはダメ。

```go
// go part
type A struct {
	X int
}

func convert(buf []byte) *A {
	if len(buf) >= unsafe.Sizeof(A{}) {
		return (*A)(unsafe.Pointer(&buf[0]))
	}
	return nil
}
```

必ず cgo を使う。int まわりのサイズやアライメントも cgo が面倒を見てくれる。

```go
/*
struct a {
	int X
}
*/
import "C"
import "unsafe"

type A C.struct_a

const SizeofA = C.sizeof_struct_a

func convert(buf *[SizeofA]byte) *A {
	return (*A)(unsafe.Pointer(buf))
}
```

cross compile との関係もあり、build 時に cgo 必須にしたくない場合は、あらかじめ godefs を出力しておくとよい。

ちなみに `[]byte` しか得られない場合は、次のようにしてもよい。

```go
func convert(buf []byte) *A {
	if len(buf) >= SizeofA {
		return (*A)(unsafe.Pointer(&buf[0]))
	}
	return nil
}
```

このようにできる理由は `unsafe` と `reflect` にある。

```
package main

import (
        "log"
        "unsafe"
        "reflect"
)

func main(){
        a := [3]byte{ 1, 2, 3 }
        b := a[:]
        log.Print(unsafe.Pointer(&a) == unsafe.Pointer(&b[0]))
        log.Print(unsafe.Pointer(&a) == unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&b)).Data))
}
```