Go でのポインターの扱い

今日は Go 言語でのポインターの扱いについて整理してみた。久しくポインターを扱う言語に触れていなかったので、ふわっと理解しているつもりだったが、色々理解できていなかったので、まとめてみる。

# 基本的なポインタ

Go での基本的なポインタの扱いは、C とそんなに変わらない。唯一違うのは、ポインタ演算ができないところだ。（プログラムを破壊する可能性があるからだろうか）

```go
package main

import "fmt"

func main() {
	str := "ushio"
	p := &str

	fmt.Println(str, "  // str")
	fmt.Println(&str, "  // &str")
	fmt.Println(p, "  // p")
	fmt.Println(*p, "  // *p")
}
```

はっきり言って文法も C と変わらない。実行結果はきっとあなたの予想通り

```
ushio   // str
0xc42006c1a0   // &str
0xc42006c1a0   // p
ushio   // *p
```

# 理解したいターゲット

実はこれを書いているのも、オープンソースへの貢献のための一歩で、次のコードをちゃんと理解したいと思ったから。

```go
// DataFactory is the DataFactory Response
type DataFactory struct {
	autorest.Response      `json:"-"`
	ID                     *string             `json:"id,omitempty"`
	Name                   *string             `json:"name,omitempty"`
	Type                   *string             `json:"type,omitempty"`
	Location               *string             `json:"location,omitempty"`
	Tags                   *map[string]*string `json:"tags,omitempty"`
	*DataFactoryProperties `json:"properties,omitempty"`
}

// DataFactoryProperties is the Property of DataFactory
type DataFactoryProperties struct {
	DataFactoryID     *string           `json:"datafactoryId,omitempty"`
	ProvisioningState ProvisioningState `json:"provisioningState,omitempty"`
	Error             *string           `json:"error,omitempty"`
	ErrorMessage      *string           `json:"errorMessage,omitempty"`
}

```
何となくでよければ正直動くものはかけるが、結局それは遅さを招くので、理解しておきたい。

# 構造体の参照渡しと、値渡し

関数やメソッドに対してのパラメータは、参照渡しという方法と、値渡しという方法がある。GO で普通に書くと「値渡し」になる。つまり、変数の値をコピーして渡す（値渡し）と、参照渡し、つまりポインタを渡す方法だ。コピーする内容が多ければ、値渡しだと時間がかかってしまう。参照渡しだとパラメータが大きな構造体出会っても、アドレスだけなので、一瞬で終わる。

さて、構造体をまるでクラスのように書くテクニックがよく使われるが、大抵は上記のターゲットもそうであるように、ポインタ渡しになっている。それには理由がある。次の例を見てみよう。

こんな構造体を作る。

```go
// Person is a person with name and age
type Person struct {
	Name   string  // Person's first name
	Age    int     // Person's age
}
```

そして、これに対応するメソッドを用意する。一つは値渡し、一つは、ポインタになっている。内容は、Ageの内容をインクリメントすることだ。

```go

// Increment increments person's age
func (p Person) Increment() {
	p.Age++
}

// IncrementWithReference increment person's age
func (p *Person) IncrementWithReference() {
	p.Age++
}
```

これらのメソッドを次のように使ってみると、実行結果が異なる。

```go
func main() {

	ushio := Person{
		Name: "tsuyoshi",
		Age:  46,
	}

	ushio.Increment()
	fmt.Println("Value: ", ushio.Age, " // 47と思いきや違う")
	ushio.IncrementWithReference()
	fmt.Println("Pointer: ", ushio.Age, " // 実際に47になった")
```

実行結果

```
Value:  46  // 47と思いきや違う
Pointer:  47  // 実際に47になった
```

値渡しの方は、Age をインクリメントしているにもかかわらず、構造体の値が変化していない。これらの関数は次のように展開される

```go
func Increment(p Person) {
   p.Age++
}

fun IncrementWithReference(p *Person) {
   p.Age++
}
```
つまり第一引数として、構造体の引数が渡っているのと同じである。だから、値渡しにしてしまうと、コピーが渡されるので、更新がうまくいかない。だから、値渡しにしていいケースは、Immutable なケースなどが考えられるが、それ以外には、基本的にはポインタ渡しの方がイメージにあう。

# ポインタと値渡しパラメータに対するシンタックスシュガー

Go はポインタの操作ができない。また、しょっちゅうポインタの値を操作することになる。面倒なので、シンタックスシュガーで、本来ポインターであっても、`p.Age++` のように、値渡しのようなイメージで書くことが可能になっている。（だから、たまに、どっちだかわからなくなっていた。なるほど。）

先ほどのゴールに対してまだ理解できていないポイントがある。それは、構造体の フィールド がポインタになっていることである。何故わざわざこうなっているのだろう？

# 構造体の フィールド が ポインタである理由

ゴールの構造体と比べて違うところは何かというと、構造体を初期化した時の、初期化の挙動による。構造体を初期化すると、値を与えないと、デフォルト値が採用される。

```go
// Person is a person with name and age
type Person struct {
	Name   string  // Person's first name
	Age    int     // Person's age
	Status *string // Person's status
}
```

先ほどの構造体に、ポインタのフィードを足してみる。そして、次のようなコードを書いて、初期化のデフォルト値の違いを見てみる。

```go
	aPerson := new(Person) // No parameter

	fmt.Println("Name :", aPerson.Name)
	fmt.Println("Age :", aPerson.Age)
	fmt.Println("Status :", aPerson.Status)
```

結果は

```
Name : 
Age : 0
Status : <nil>
```

初期化したら、型ごとのデフォルト値で埋められる。ちなみに、元々のゴールの構造体の使い道は、REST API から帰ってきた値をを保存するためのものである。JSON から変換されてくる。この構造体の必須チェックを行うときに、値渡しだと、から文字が、初期値によるものなのか、から文字が渡されたのかがわからなくなってしまう。ちなみに、参照渡しにすると、値の参照が多少面倒になる。例えば、`*string` のフィールドがあるときに、`&"tsuyoshi"` などと書いても、参照渡しはできない。たぶんこんなメソッドを書くなり、一旦変数に代入して、アドレスをもらうなりしないといけない。面倒だ。

```go
func toAddress(str string) *string {
	return &str
}
```

ゴールの構造体で参照渡しになっているのは、JSONからパースするので、nil か　から文字かを明確に区別したかったのだと思う。そして、構造体のフィールドの更新はない（REST-API から受け取った値を格納する責務なので）だから、今回はポインタを選択しているのだと思う。

# ネストした構造体

では最後のテクニック

```go
// Person is a person with name and age
type Person struct {
	Name   string  // Person's first name
	Age    int     // Person's age
	Status *string // Person's status
}
```

を使って

```go

// Employee is an employee
type Employee struct {
	Person
	ID int // Employee's employee_id
}
```

こんな感じで書くと、継承っぽいイメージで使えるようになる。具体例を見てみよう。初期化時はPersonを意識しているが、使うところは、まるで継承したようなイメージになっている。

```go

	emp := Employee{
		Person: Person{Name: "tsuyoshi",
			Age:    46,
			Status: toAddress("Happy"),
		},
		ID: 2014,
	}

	fmt.Println("Name: ", emp.Name)
	fmt.Println("Age: ", emp.Age)
	fmt.Println("Status: ", *emp.Status, "(", emp.Status, ")")
	fmt.Println("Id: ", emp.ID)

```

実行結果

```
Name:  tsuyoshi
Age:  46
Status:  Happy ( 0xc42000e350 )
Id:  2014
```

うん。しっかりまるで継承しているかのようだ。これで大体ポインターの部分はつかめたきがする。他にも押さえておくべき文法がありましたら、ぜひコメントお願いいたします。

# リソース

今回はたくさん参照しましたので、リストを書いておきます。

* [Go 言語の値レシーバとポインタレシーバ](https://skatsuta.github.io/2015/12/29/value-receiver-pointer-receiver/)
* [Effective Go](https://golang.org/doc/effective_go.html)
* [A Tour of Go: Pointers](https://tour.golang.org/moretypes/1)