15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Go で関数に渡したポインタの値を変更するには

Posted at

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" という新しい文字列を代入することで、値を変更することができました。

所感

とても基礎的なところですが、よくわからなくなるためまとめてみました。
参考になりましたら、嬉しいです。

参考

15
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?