new
やmake
を使って変数宣言したりappend
を使ってスライスの追加なんかを自然とやってきたけど、ふとこれは何だっけと思って調べてみました。
するとビルトインパッケージとして参照することができた。
ソースを見た感じgodoc用に見えるので中身は説明を読んで使ってみる必要がある。
この辺は知らないと使えないものなのでおさらいしておきます。
標準出力
- func print(args …Type)
- func println(args …Type)
fmt.Print
やfmt.Println
と似たような動きちょっとした出力用途で使える。
1 2 3 4 5 6 7 8 9 10 |
print("a") println("b") print("c") print("d") print("e") println("f") /*Output: ab cdef */ |
ただ自動で型推定なんかはしてくれないので結局fmt
を使うことになると思う。
メモリ(容量)管理系
- func new(Type) *Type
- func make(t Type, size …IntegerType) Type
混同しやすいけどnew
はゼロ値で確保された値へのポインタを得る関数で、make
はマップ、スライス、チャンネル(map[type]type
, []type
, chan
)の確保と初期化を行い型そのものを得る関数です。
この3つは型そのものがポインタを持っているのでmake
で型を得ています。
それ以外のstruct
定義したものなんかは容量を気にして渡しやすいポインタをnew
で得る思っておけばとりあえず間違いはないはず。
試しにスライスでこんなことをする。
1 2 3 4 5 |
a := []int{} b := new([]int) c := make([]int, 0) fmt.Printf("%#v %#v %#v\n", a, b, c) //[]int{} &[]int(nil) []int{} fmt.Println(unsafe.Sizeof(a), unsafe.Sizeof(b), unsafe.Sizeof(c))//24 8 24 |
new
で確保した場合のサイズは8(つまりポインタだけ)ですね。
スライスはpointer, len(int), cap(int)の24バイトとなるのが正しい動作です。
まあnew
で作ってもこんな風に使っていけなくもないですが。
1 |
*b = append(*b, 55) |
- func append(slice []Type, elems …Type) []Type
- func copy(dst, src []Type) int
スライスの追加とコピーの関数です。
append
は確保した容量に追加する形の非破壊的な関数です。
1 2 3 4 |
a := make([]int, 2) a = append(a, 3) b := append(a, 4, 5) fmt.Println(a, b) //[0 0 3] [0 0 3 4 5] |
copy
はいわゆるディープコピー。スライスは型ですが中身のポインタが代入されるため参照渡しのようになってしまいます。
1 2 3 4 5 |
a := make([]int, 1) a[0] = 1 b := a b[0] = 9 fmt.Println(a, b)//[9] [9] |
そこでcopy
ですが、する側の容量がされる側の容量より大きくないとindex out of range
エラーになります。
また大きい部分に関しては無視されます。
1 2 3 4 5 6 7 |
a := make([]int, 1) b := make([]int, 3) a[0] = 1 b[0] = 2 b[1] = 3 copy(b, a) fmt.Println(a, b) //[1] [1 3 0] |
ちなみにスライスに削除はないので使わない方法を探すか実装の必要があります。
- func delete(m map[Type]Type1, key Type)
マップの削除に使います。
1 2 3 4 5 6 |
a := make(map[string]int, 0) a["a"] = 1 a["b"] = 2 a["c"] = 3 delete(a, "b") fmt.Println(a)//map[a:1 c:3] |
スライスで削除できないこともあって、個人的には順不同ならmap
を使うことが多いです(range
ではmap
の順序は保証されない)。
1 2 3 4 5 6 7 |
//ポインタでアクセスさせて変に重くならないようにしたり a := make(map[*SomeStruct]bool, 0) //struct{}のサイズが0なのを利用してもいいけどコードが読みにくくなるのでしていない s := new(SomeStruct) a := map[*SomeStruct]struct{}{} a[s] = struct{}{} |
- func cap(v Type) int
- func len(v Type) int
cap
はメモリ確保した長さでlen
は汎用的な長さを返す関数です。
1 2 3 4 |
a := make([]int, 10) a = append(a, 1) fmt.Println(len(a))//11 fmt.Println(cap(a))//20 |
この例のスライスはappend
によるメモリ再確保で11までの領域が使用可能になり、元の10の倍の20分のメモリが確保されています。
型ごとに動作が違うので詳しくは原文参照。
- func close(c chan<- Type)
チャンネル終了用。
make(chan Type)
したものはちゃんとclose
させましょう。
例外
- func panic(v interface{})
- func recover() interface{}
ルーチンを止めたり、復帰させたりする。
通常用途ではあまり使うべきものでもない。
1 2 3 4 5 6 |
defer func() { if e := recover(); e != nil { fmt.Println("recover panic:", e) } }() panic("occur panic") |
複素数
- func complex(r, i FloatType) ComplexType
- func real(c ComplexType) FloatType
- func imag(c ComplexType) FloatType
これも普段使う機会はないけど複素数作成用と実数、虚数の取得用。