この頃担当しているシステムで、`make()`関数をよく見かけます。少し気になったので調べてみました。
make()関数
スライス(slice)、マップ(map)、チャネル(channel)といった、Goの参照型を生成するときに使う組み込み関数です。それぞれの参照型に対して2つずつ、呼び出し方が用意されています。ここではさらっと、その中身を見ていくことにします。
スライスのmake
スライスは、他の言語でいうところの「可変長配列」を表現する型です。`make(T, n)`を使うことで、要素数と容量がnであるT型のスライスを生成できます。
package main
import "fmt"
func main() {
strs := make([]string, 3)
fmt.Println(strs)
}
$ go run main.go
[ ]
また、`make(T, n, m)`を使うことで、要素数がnで容量がmであるT型のスライスをつくれます。ここで「要素数」と「容量」の関係ですが、ざっくりいうと「なかみ」と「はこ」です。たとえば要素数=「なかみ」が2で容量=「はこ」が3のスライスは生成できますが、要素数=「なかみ」が3で容量=「はこ」が2のスライスは生成できません。
func main() {
strs := make([]string, 3, 2)
fmt.Println(strs)
}
$ go run main.go
# command-line-arguments
./main.go:6:14: len larger than cap in make([]string)
マップのmake
マップについては、`make(T)` でT型のマップを、`make(T, n)`でT型のマップを要素数nをヒントにして生成できます。
ここで「要素数nをヒントにして生成」とは、いわば「その要素数が入る分のメモリ領域を確保しといてね」とGoのランタイムにお願いする、というようなイメージです。たとえば、10万ほどの要素が追加されると見込まれるような時にこのmake(T, n)を使うと、パフォーマンス向上も見込める場合があります。
func main() {
strs := make(map[int64]string)
strs[1] = "First"
strs[2] = "Second"
strs[3] = "Three"
// 10000要素が入るくらいのメモリを確保してもらう
ints := make(map[string]int32, 10000)
ints["one"] = 1
ints["two"] = 2
ints["three"] = 3
fmt.Println("make(T):", strs)
fmt.Println("make(T, n):", ints)
}
チャネルのmake
Go言語では「go文」を用いて、非同期に複数実行されるゴルーチンを生成できます。チャネルは、あるゴルーチンと別のゴルーチンの間でデータの受け渡しができるようデザインされた、Goに特有の型です。`make(T)`によって、「バッファ」のサイズが0のチャネルを生成できます。
チャネルのバッファ
そもそもチャネルは、「キュー(Queue, 待ち行列)」の性質を備えたデータ構造です。チャネルにおけるバッファとは、このキューを格納しておくための領域だとみなせます。先の`make(T)`は、このバッファのサイズが0のチャネルを生成する、ということです。もしバッファサイズをnだと指定するときは、`make(T, n)`が使えます。
返信がありません