はじめに
この記事は、エンジニア経験1年の大学生が実務や個人の学習で勉強になったこと、詰まったことをまとめています。間違っている箇所などがございましたら、指摘していただけると幸いです。
背景
今まで恥ずかしながらポインタという概念を理解できていませんでした。なので、今回Goを新たに学習するにあたって、ポインタにつまずいたので、記事にして理解を深めようと思いました。
※自分なりに整理した記事であり、参考にならないかもしれないのでご了承下さい。
環境
- Go 1.18.1
ポインタとは?
ポインタとは値のメモリアドレスを指す。
func main() {
var n int = 1
fmt.Println(n) // => 1
fmt.Println(&n) // => 0xc0000bc008
}
Goでは変数に&
を付けることで、その変数のメモリアドレスを取得できる。 なので、0xc0000bc008
がメモリアドレスとなる。では、メモリアドレスとは何なのか。
メモリアドレスとは?
コンピュータにはメモリと呼ばれる場所が存在し、変数はそのメモリに記録されており、その場所をアドレスと呼ぶ。その名の通り、メモリ内のアドレス(場所)である。メモリアドレスは0xc0000bc008
となっている。
ポインタ型変数とは?
func main() {
var n int = 1
var p *int = &n
fmt.Println(p) // => 0xc0000ba008
}
その名の通り、ポインタ(メモリアドレス)が代入された変数である。また、ポインタ型変数を定義するには*(アスタリスク)
をつけて定義する。
ポインタからアクセスする
func main() {
var n int = 1
var p *int = &n
fmt.Println(p)
fmt.Println(*p) // => 1
}
ポインタ型変数に対して、*変数名
でポインタが示す変数名の値を取得することができる。*p
とすることで、変数p
の値が取得できる。
ポインタの書き換え
func main() {
name := "坂本勇人"
var namePtr *string = &name
*namePtr = "李承燁"
fmt.Println(name) // => 李承燁
}
ポインタ型変数を使用して、値を更新することもできる。更新するには*変数名 = 更新する値
と記述する。また、ポインタの書き換えで値渡しと参照渡しの理解が必要になってくる。
値渡し
func main() {
var name string = "坂本勇人"
favoriteBaseballPlayer(name)
fmt.Println(name) // => 坂本勇人
}
func favoriteBaseballPlayer(name string) {
name = "菅野智之"
}
favoriteBaseballPlayer(name)
で渡したのはname
のコピーなのでname
自体の値は変わらない。つまり、値渡しをしているということである。
参照渡し
func main() {
var name string = "坂本勇人"
favoriteBaseballPlayer(&name)
fmt.Println(name) // => 菅野智之
}
func favoriteBaseballPlayer(name *string) {
*name = "菅野智之"
}
favoriteBaseballPlayer(&name)
で変数nameのアドレスを渡している。なので、name
自体の値が変わる。つまり、参照渡しをしているということである。
まとめ
今回このように記事にすることでポインタについて整理することができ、理解が深まったと思います。Rubyではポインタを意識することは無かったので、とても勉強になりました。同じように今までポインタの概念を知らなかった人などに少しでも参考になれば幸いです。