雑なメモ書き

気楽にいきます

goのmakeで起こりがちな悲劇

  • goのmakeを使っていると第3引数をあんまり使わないから
  • これ挙動なんだったっけとなるのでメモする
  • https://golang.org/pkg/builtin/

make(len:0)によるslice作成

  • よくあるやつ
  • 想像通りの結果
// cap: 0
v := make([]string, 0)

pp.Print(v)
fmt.Printf("len:%d,cap:%d\n", len(v), cap(v))

v = append(v, "hello")

pp.Print(v)
fmt.Printf("len:%d,cap:%d\n", len(v), cap(v))
  • 結果
[]string{}len:0,cap:0

[]string{
  "hello",
}len:1,cap:1

make(len:10)による起こりがちな悲劇

  • 気を利かせて先に領域を確保したはずなのに
  • 空の配列が出来てしまい
  • バグの要因になり
  • 更にappendすると無駄に領域を食べるという悲劇
// len:10
v := make([]string, 10)

pp.Print(v)
fmt.Printf("len:%d,cap:%d\n", len(v), cap(v))

v = append(v, "hello")
pp.Print(v)
fmt.Printf("len:%d,cap:%d\n", len(v), cap(v))

// cap: 10
v = make([]string, 0, 10)
  • 結果
[]string{
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
}len:10,cap:10
[]string{
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "",
  "hello",
}len:11,cap:20

makeで先に領域を確保しておきたい正しい書き方

  • 第3引数だけを指定
  • これにより、領域だけは確保されて
  • 空文字列の悲劇は起きない
  • appendしても無駄に増えない
// cap: 10
v := make([]string, 0, 10)

pp.Print(v)
fmt.Printf("len:%d,cap:%d\n", len(v), cap(v))

v = append(v, "hello")
pp.Print(v)
fmt.Printf("len:%d,cap:%d\n", len(v), cap(v))
  • 結果
[]string{}len:0,cap:10
[]string{
  "hello",
}len:1,cap:10