Skip to content

Go ポインタ

Go はポインタを維持し、ある程度パフォーマンスを保証しながら、より良い GC と安全性のためにポインタの使用を制限しています。

作成

ポインタには 2 つのよく使用される演算子があります。1 つはアドレス演算子 & で、もう 1 つは参照解除演算子 * です。変数のアドレスを取得すると、対応する型のポインタが返されます。例を以下に示します。

go
func main() {
   num := 2
   p := &num
   fmt.Println(p)
}

ポインタは変数 num のアドレスを格納します。

0xc00001c088

参照解除演算子には 2 つの用途があります。1 つ目はポインタが指す要素にアクセスすること、つまり参照解除です。例を以下に示します。

go
func main() {
  num := 2
  p := &num
  rawNum := *p
  fmt.Println(rawNum)
}

p はポインタです。ポインタ型を参照解除すると、ポインタが指す要素にアクセスできます。もう 1 つの用途はポインタを宣言することです。例を以下に示します。

go
func main() {
   var numPtr *int
   fmt.Println(numPtr)
}
<nil>

*int は、その変数の型が int 型のポインタであることを表します。ただし、ポインタは宣言するだけでなく、初期化する必要があります。メモリを割り当てる必要があります。空ポインタのままでは正常に使用できません。アドレス演算子を使用して他の変数のアドレスを代入するか、組み込み関数 new を使用して手動で割り当てる必要があります。例を以下に示します。

go
func main() {
   var numPtr *int
   numPtr = new(int)
   fmt.Println(numPtr)
}

より多くは短変数を使用します。

go
func main() {
   numPtr := new(int)
   fmt.Println(numPtr)
}

new 関数のパラメータは型のみで、対応する型のポインタを返します。関数はそのポインタにメモリを割り当て、ポインタが指す値は対応する型のゼロ値になります。例を以下に示します。

go
func main() {
   fmt.Println(*new(string))
   fmt.Println(*new(int))
   fmt.Println(*new([5]int))
   fmt.Println(*new([]float64))
}

0
[0 0 0 0 0]
[]

ポインタ演算の禁止

Go ではポインタ演算はサポートされていません。つまり、ポインタはオフセットできません。まず C++ のコードを見てみましょう。

cpp
int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *p = &arr[0];
    cout << &arr << endl
         << p << endl
         << p + 1 << endl
         << &arr[1] << endl;
}
0x31d99ff880
0x31d99ff880
0x31d99ff884
0x31d99ff884

配列のアドレスと配列の最初の要素のアドレスが一致し、ポインタに 1 を加算すると、配列の 2 番目の要素を指すことがわかります。Go の配列も同様ですが、違いはポインタがオフセットできないことです。例を以下に示します。

go
func main() {
   arr := [5]int{0, 1, 2, 3, 4}
   p := &arr
   println(&arr[0])
   println(p)
   // ポインタ演算を試みる
   p++
   fmt.Println(p)
}

このようなプログラムはコンパイルできません。エラーは以下の通りです。

main.go:10:2: invalid operation: p++ (non-numeric type *[5]int)

TIP

標準ライブラリ unsafe は低レベルプログラミングのための多くの操作を提供しており、ポインタ演算も含まれています。詳細は 標準ライブラリ -unsafe をご覧ください。

new と make

前のいくつかのセクションで組み込み関数 newmake について何度も言及してきました。両者は似ていますが、異なる点もあります。以下で復習します。

go
func new(Type) *Type
  • 戻り値は型ポインタ
  • 受信パラメータは型
  • ポインタ用のメモリ領域割り当て専用
go
func make(t Type, size ...IntegerType) Type
  • 戻り値は値、ポインタではない
  • 最初の受信パラメータは型、可変長パラメータは渡された型によって異なる
  • スライス、マップ、チャネル用のメモリ領域割り当て専用

以下にいくつかの例を示します。

go
new(int) // int ポインタ
new(string) // string ポインタ
new([]int) // 整数型スライスポインタ
make([]int, 10, 100) // 長さ 10、容量 100 の整数型スライス
make(map[string]int, 10) // 容量 10 のマップ
make(chan int, 10) // バッファサイズ 10 のチャネル

Golang学习网由www.golangdev.cn整理维护