最終更新:2020/05/01
ポインタはメモリのメモリのアドレス情報です。
ポインタを使うと、アドレスを通じて呼び出し元の変数の値を変更することができます。
ポインタは * 演算子 を使います。
例を提示します。
int型のポインタを宣言する場合は
var pointer *int
と宣言します。
構造体(struct)のポインタ
structの場合は
user := &model.User{}
と宣言します。
& を用いることで変数のアドレスの取得ができます。
このパターンは、ORMライブラリのgormなどでよく使うパターンです。
// FindByID finds an User object.
func (impl userImpl) FindByID(ID int) (*model.User, error) {
user := &model.User{}
if err := impl.db.Where("id = ?", ID).Find(user).Error; err != nil {
return nil, err
}
return user, nil
}
アドレスから変数の中身にアクセス
アドレスから変数の中身へアクセスする時は * を使います。
var pUserID *int
*pUserID
いつ使うべきか
ポインタが利用されるケースは以下です。
- 既存コードや外部ライブラリの関数が、引数にポインタ型を取る場合
- サイズの大きいstructやarrayを扱う場合
- nilを扱いたい場合
具体的な例を提示します。
既存コードや外部ライブラリの関数が、引数にポインタ型を取る場合
ORMライブラリのgormでは、Find関数などの引数はポインタ型を渡すように実装されています。
user := &model.User{}
if err := impl.db.Where("id = ?", ID).Find(user).Error; err != nil {
return nil, err
}
サイズの大きいstructやarrayを扱う場合
sqlを発行して結果を取得してオブジェクトを返す場合も、ポインタ型で返すようにします。
func (impl userImpl) FindByID(ID int) (*model.User, error) {
user := &model.User{}
if err := impl.db.Where("id = ?", ID).Find(user).Error; err != nil {
return nil, err
}
return user, nil
}
nilを扱いたい場合
データがない場合の状態を扱いたい場合が多々あります。 その場合もポインタ型で宣言します。
category *int
引数や返り値をポインタにするか、値にするか
関数の引数、メソッドの引数を、値にすべきかポインタにすべきかはGoの実装の悩みポイントです。
公式サイトに説明がありますが、まとめると以下になります。
- 値を変える必要があるならポインタ
- 引数が大きければポインタ
- 引数が小さければ値
大きい小さいは人によって感覚が異なるので、プロジェクトによって上限を決めると良いでしょう。