2時に寝て7時に起きた。深夜に葬送のフリーレン10巻を読んでからなんとなく眠れなくて夜更かししてた。木曜日は会議がなくて自分のために時間を使える。機能開発に集中して実装していた。
go の学び直し
Gopher塾 #4 - 私も解説できるポインタ - DAY1 に参加した。
今日のテーマはポインタ。tenntenn さんが話すのだから深い内部実装の話しなどもあるのかな?と期待していたけれど、これは基本的な go のポインタの扱いを学ぶ講義だった。私にとっては9割は知っていることだった。それでも1割は知らないことがあったので参加して勉強にはなった。この歳になると本やイベントから1-2割学べたら十分だと思う。go は内部的にすべて値渡しで何でもコピーするするといった振る舞いをする。ポインタを渡すと、ポインタの値であるアドレスをコピーすることでプログラムが動く。コピーなので大きな構造体をそのまま渡すとその分のメモリのオーバーヘッドがあって遅くなったりする。ポインタならアドレスだけのコピーで済む。
go には参照の概念はないという説明があって、ポインタと参照は別の概念なんだと今更ながらに気付いた。gpt-4 にポインタと参照の違いを尋ねたりしていた。参照は初期化後に変更できなかったり、null を参照できなかったり、ポインタ演算のようなことができなかったりすることで安全にプログラミングするための言語機能と言える。一般的には参照はポインタを使って実装される。ポインタの方が低レイヤで制約が少ないと言える。参照はポインタの一部の機能を安全にプログラマーに提供していると言える。
次に go のポインタの特徴をまとめる。
- 型付け
- ポインタは型付けされていて、特定の型の変数のアドレスだけがその型のポインタに割り当てられる
- アドレス演算子とデリファレンス演算子
- これらを単項演算子と呼ぶ
- アドレス演算子 (&) で変数のアドレスを取得してポインタを作成する
- デリファレンス演算子 (*) でポインタが指すアドレスに格納されている値にアクセスする
- ポインタ演算制限
- ポインタ演算は許可されていない、メモリアクセスの誤りやセキュリティ上の問題が軽減される
- new と make 関数
- new 関数を使うと指定された型の新しい変数を作成してそのアドレスを返す
- make 関数は、スライス、マップ、チャネルなどの複合データ構造を作成および初期化して、それらへのポインタを返す
- ポインタの nil 値
- ポインタは、無効なアドレスを表す特別な値である nil をもてる
- nil ポインタにアクセスしようとすると、実行時に panic が発生する
- メソッドレシーバとしてのポインタ
- メソッドレシーバとしてポインタを使うとメソッド内でレシーバオブジェクトの変更ができる
- 値レシーバは意図せぬ不具合を招く可能性があるから基本的にはポインタレシーバを使う方がよいのではないかといった話しもあった
- メソッドレシーバとしてポインタを使うとメソッド内でレシーバオブジェクトの変更ができる