TL;DR
package main
func change(s *string) {
*s = "changed"
}
func main() {
s := "hoge"
change(&s)
fmt.Println(s)
}
解説
Go ではポインタを扱えることができますが、 &
や *
をどうつけたらいいか、よくわからなくなってしまいがちです。
まずは一旦整理してみます。
構文
整理すると、2 種類の構文があるのではないかと思います。
演算子として利用される場合
-
&
は値型変数からポインタ(メモリのアドレス)型変数を取得する演算子 -
*
はポインタ型変数から値型変数を取得する演算子
var tmp string = "tmp"
// ポインタ
tmpPointer := &hoge
// 値
tmpValue := *tmpPointer
fmt.Println(tmpPointer) // 0x40c128
fmt.Println(tmpValue) // tmp
型として利用される場合
*
は任意の型のポインタ型
// ポインタ型
type stringPointer *string
回答
ここでは関数にポインタ型を渡して、ポインタが指す値を変更したいと考えています。
状況的には、以下のような形です。
func change(s *string) {
// 値を変換する。
}
補足
そもそも、なぜポインタ型を渡す必要があるかですが、値型の場合は関数内での変更が関数外へ伝搬しないためです。つまり、関数内で引数の値をいくら変更しても、関数の呼び出し元には一切影響しません。
これは、Go の引数の受け渡し方が値渡し (値をコピーして関数に渡す方法) に由来します。
実際の変更コードですが、以下になります。
func change(s *string) {
*s = "changed"
}
まず、関数の引数の s
ですが、ポインタ型になっています。Go の関数は値渡しで引数をわたすので、s
はポインタ型変数のコピーになっています。ですが、ポインタ型の変数の中身(アドレス)がコピーされただけなので、ポインタが指す先の値は同じになっています。
つまり、関数内でポインタが指す先の値を変更することで、値を変更することができます。
実際の値取得ですが、変数 s
はポインタ型のため、 *
演算子をつけることで取得できます。取得した値に "changed" という新しい文字列を代入することで、値を変更することができました。
所感
とても基礎的なところですが、よくわからなくなるためまとめてみました。
参考になりましたら、嬉しいです。