## 概要 [[Go]]の関数について、引数を値で渡すかポインタで渡すかモヤモヤしているので、挙動とあわせて整理する。具体的には引数が[[値渡し]]なのか、[[参照渡し]]なのか、[[参照の値渡し]]なのかを調べる。 ## 結論 **値がnullableの場合のみ**ポインタを渡す。それ以外はポインタを渡さない。 - [[構造体 (Go)|構造体]]について - パフォーマンスが本当に問題になったとき初めてポインタで渡すことを検討する ## 関数に引数を渡すときの仕様 | 引数型 | 渡し方 | 備考 | | ------------------- | ---------- | ------------------------------------------ | | int | [[値渡し]] | | | string | [[値渡し]] | | | 構造体 | [[値渡し]] | ネストした[[フィールド (Go)\|フィールド]]も含めてdeep copyされる | | [[スライス (Go)\|スライス]] | [[参照の値渡し]] | **要素はdeep copyされない** | ## 引数渡しの具体例 ### intの例 ```go func hoge(arg int) { arg = 999 } func main() { x := 1 hoge(x) fmt.Printf("x = %#v\n", x) // x = 1 } ``` ### stringの例 ```go func hoge(arg string) { arg = "aaaaaaaaaaaaaaaaaaaaaa" } func main() { x := "hoge" hoge(x) fmt.Printf("x = %#v\n", x) // x = "hoge" } ``` ### 構造体の例 ```go type human struct { id int name string } func hoge(arg human) { arg = human{ id: 777, name: "ラッキーマン", } } func main() { x := human{ id: 1, name: "イチロー", } hoge(x) fmt.Printf("x = %#v\n", x) // x = main.human{id:1, name:"イチロー"} } ``` [[構造体 (Go)|構造体]]は要素も含めてdeep copyされるので、[[フィールド (Go)|フィールド]]を変更しても元データには影響しない。 ```go func hoge(arg human) { arg.id = 777 } func main() { x := human{ id: 1, name: "イチロー", } hoge(x) fmt.Printf("x = %#v\n", x) // x = main.human{id:1, name:"イチロー"} } ``` これはネストする[[構造体 (Go)|構造体]]でも同じ。 ```go type animal struct { name string } type human struct { id int name string pet animal } func hoge(arg human) { arg.pet = animal{ name: "セイキチ", } // arg.pet.name = "セイキチ" でも同じ } func main() { x := human{ id: 1, name: "イチロー", pet: animal{ name: "タツヲ", }, } hoge(x) fmt.Printf("x = %#v\n", x) // x = main.human{id:1, name:"イチロー", pet:main.animal{name:"タツヲ"}} } ``` なお、[[Go]]は[[参照渡し]]をサポートしていないので、たとえポインタを[[実引数]]として渡した場合に[[仮引数]]への再代入をしても、[[実引数]]への影響は一切ない。 ```go func hoge(arg *human) { arg = &human{ id: 0, name: "", } } func main() { x := human{ id: 1, name: "イチロー", } hoge(&x) fmt.Printf("x = %#v\n", x) // x = main.human{id:1, name:"イチロー"} } ``` ### スライスの例 ```go func hoge(arg []int) { arg = []int{1, 8, 0, 7, 0, 2} } func main() { xs := []int{1, 2, 3} hoge(xs) fmt.Printf("xs = %#v\n", xs) // xs = []int{1, 2, 3} } ``` ただし、[[スライス (Go)|スライス]]の要素はdeep copyされないので注意。元データに影響が出る。 ```go func hoge(arg []int) { arg[0] = 180702 } func main() { xs := []int{1, 2, 3} hoge(xs) fmt.Printf("xs = %#v\n", xs) // xs = []int{180702, 2, 3} } ```