Goのポインタの基本
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 19/107。
ポインタは、別の変数のメモリ番地(メモリアドレス)を格納する変数です。値を直接保持するのではなく、その値がメモリ上のどこにあるかという場所を保持します。ポインタはGoにおいて基本的であり、効率的なデータ操作に不可欠です。
ポインタを作成するには、&演算子を使用して変数のアドレスを取得し、*演算子を使用してポインタ型を宣言したり、そのアドレスにある値にアクセスしたりします。
x := 42
p := &x // pはxのメモリアドレスを保持します
fmt.Println(p) // 0xc000018030 (メモリアドレス)
fmt.Println(*p) // 42 (そのアドレスにある値)& 演算子は「〜のアドレス」を意味し、ポインタを返します。* 演算子は、ポインタに対して使用されると「〜の値」を意味し、デリファレンス(間接参照)と呼ばれます。また、ポインタを介して元の値を変更することもできます。
x := 10
p := &x
*p = 25 // ポインタを介して値を変更する
fmt.Println(x) // 25 (元の変数が変更される)ポインタ型は *T と記述されます。ここで T は指し示される型です。int へのポインタは *int 型になります。
var p *int // intへのポインタを宣言します
x := 100
p = &x // pは現在xを指していますポインタのゼロ値は nil であり、これは何も指していないことを意味します。nilポインタをデリファレンスしようとするとランタイムパニックが発生するため、使用前に必ずポインタが初期化されていることを確認してください。
チャレンジ
簡単メモリ番地を介して変数を変更するポインタの力を示す、シンプルな値の入れ替えプログラムを作成しましょう。
コードは2つのファイルに分けて構成します:
swap.go: 2つの*intポインタをパラメータとして受け取るSwapValuesという関数を作成します。この関数は、これらのポインタが指す値を入れ替える必要があります。呼び出し後、各変数はもう一方の元の値を保持している必要があります。この関数は何も返しません。ポインタを介して直接値を変更します。main.go: 入力から2つの整数を読み取って変数に格納し、SwapValues関数を使用してそれらの値を交換します。変更を示すために、入れ替えの前と後の両方の値を表示してください。
以下の入力が提供されます:
- 1行目: 1つ目の整数
- 2行目: 2つ目の整数
出力形式:
Before: a=[first] b=[second]
After: a=[first] b=[second]例えば、10 と 25 が与えられた場合、出力は以下のようになります:
Before: a=10 b=25
After: a=25 b=10関数に変数を渡すときは & 演算子を使用し、関数内で実際の値にアクセスして変更するときは * 演算子を使用することを忘れないでください。
チートシート
ポインタは、別の変数のメモリ番地(アドレス)を格納する変数です。変数のアドレスを取得するには & 演算子を使用し、ポインタ型を宣言したり、そのアドレスにある値にアクセスしたりするには * 演算子を使用します。
x := 42
p := &x // p holds the memory address of x
fmt.Println(p) // 0xc000018030 (memory address)
fmt.Println(*p) // 42 (value at that address)& 演算子は「〜のアドレス」を意味し、ポインタを返します。ポインタに対して * 演算子を使用すると「〜にある値」を意味し、これをデリファレンス(間接参照)と呼びます。
ポインタを介して元の値を変更することができます:
x := 10
p := &x
*p = 25 // change value through pointer
fmt.Println(x) // 25 (original variable changed)ポインタ型は *T と記述されます。ここで T は指し示される型です:
var p *int // declares a pointer to int
x := 100
p = &x // p now points to xポインタのゼロ値は nil です。nilポインタをデリファレンスしようとすると、実行時パニックが発生します。
自分で試してみよう
package main
import "fmt"
func main() {
// 入力から2つの整数を読み取る
var a, b int
fmt.Scanln(&a)
fmt.Scanln(&b)
// 入れ替え前の値を表示する
fmt.Printf("Before: a=%d b=%d\n", a, b)
// TODO: a と b へのポインタを使用して SwapValues 関数を呼び出す
// アドレスを渡すために & 演算子を使用することを忘れないでください
// 入れ替え後の値を表示する
fmt.Printf("After: a=%d b=%d\n", a, b)
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー