Goのポインタについて、よく分からなかったので、図を交えて理解してみました。
下記のようなコードがあるとします。
package main
import "fmt"
func main() {
var name = "taro"
}
メモリ上では下記のような概略図となっています。
型の前に*がついている場合「ポインタ変数」となります。
ポインタ変数には、メモリのアドレスが格納されています。
var pv *string
上記の場合のpvに格納されたアドレスのメモリにはstring型のデータが格納されているという意味となります。
イメージは下記の図のようになります。
当然、下記のような式はコンパイルエラーとなります。
package main
import "fmt"
func main() {
var name = "taro"
var pv *string
pv = "hello" //ここでコンパイルエラー
}
//pvにはメモリのアドレスが格納されるのでstring型のデータをを直接入れることはできない。
変数の前に&がついた場合は、その変数が指し示すメモリのアドレスを参照します。
package main
import "fmt"
func main() {
var name string = "taro"
var pv *string = &name
}
メモリ上では下記のような概略図となっています。
また、下記のコードもコンパイルエラーとなります。
package main
func main() {
var name = 123
var pv *string
pv = &name //ここでコンパイルエラー
}
//nameが格納されているアドレスを仮に11111111とする。
//pvには&nameにより、name変数のメモリ(つまり11111111)が格納されようとしている。
//pvは本来、string型の値を持つメモリのアドレスしか格納できない。(var pv *string)
//しかし、int型の値を持つメモリのアドレスを入れようとしている。(pv = &name)
//よって、エラーとなる。
ポインタ変数の前に*をつけると格納されたアドレスのメモリに格納された値を参照します。
下記のようなコードがあるとします。
package main
import "fmt"
func main() {
var name string = "taro"
var pv *string = &name
fmt.Println(*pv)
}
>> taro
メモリ上では下記のような概略図となっています。
以下のようなコードの場合は、関数外のnameには影響しません。
package main
import "fmt"
func main() {
var name string = "taro"
rename(name)
fmt.Println(name)
}
func rename(name string) {
name = "yamada" + name
}
>>taro
メモリ上では下記のような概略図となっています。
※図内の関数はrename関数のことです。
以下のようなコードの場合は、関数外のnameの値が書き換わります。
package main
import "fmt"
func main() {
var name string = "taro"
rename(&name)
fmt.Println(name)
}
func rename(name *string) {
*name = "yamada" + *name
}
>> yamadataro
メモリ上では下記のような概略図となっています。
※図内の関数はrename関数のことです。
以上となります。
姉妹記事
参考にさせていただいた記事
とってもやさしいGo言語入門
https://zenn.dev/ak/articles/1fb628d82ed79b#%E6%A7%8B%E9%80%A0%E4%BD%93
ポインタを図で理解する
https://christina04.hatenablog.com/entry/pointers-in-golang
ありがとうございました。