Go ポインタ
Go はポインタを維持し、ある程度パフォーマンスを保証しながら、より良い GC と安全性のためにポインタの使用を制限しています。
作成
ポインタには 2 つのよく使用される演算子があります。1 つはアドレス演算子 & で、もう 1 つは参照解除演算子 * です。変数のアドレスを取得すると、対応する型のポインタが返されます。例を以下に示します。
func main() {
num := 2
p := &num
fmt.Println(p)
}ポインタは変数 num のアドレスを格納します。
0xc00001c088参照解除演算子には 2 つの用途があります。1 つ目はポインタが指す要素にアクセスすること、つまり参照解除です。例を以下に示します。
func main() {
num := 2
p := &num
rawNum := *p
fmt.Println(rawNum)
}p はポインタです。ポインタ型を参照解除すると、ポインタが指す要素にアクセスできます。もう 1 つの用途はポインタを宣言することです。例を以下に示します。
func main() {
var numPtr *int
fmt.Println(numPtr)
}<nil>*int は、その変数の型が int 型のポインタであることを表します。ただし、ポインタは宣言するだけでなく、初期化する必要があります。メモリを割り当てる必要があります。空ポインタのままでは正常に使用できません。アドレス演算子を使用して他の変数のアドレスを代入するか、組み込み関数 new を使用して手動で割り当てる必要があります。例を以下に示します。
func main() {
var numPtr *int
numPtr = new(int)
fmt.Println(numPtr)
}より多くは短変数を使用します。
func main() {
numPtr := new(int)
fmt.Println(numPtr)
}new 関数のパラメータは型のみで、対応する型のポインタを返します。関数はそのポインタにメモリを割り当て、ポインタが指す値は対応する型のゼロ値になります。例を以下に示します。
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++ のコードを見てみましょう。
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 の配列も同様ですが、違いはポインタがオフセットできないことです。例を以下に示します。
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
前のいくつかのセクションで組み込み関数 new と make について何度も言及してきました。両者は似ていますが、異なる点もあります。以下で復習します。
func new(Type) *Type- 戻り値は型ポインタ
- 受信パラメータは型
- ポインタ用のメモリ領域割り当て専用
func make(t Type, size ...IntegerType) Type- 戻り値は値、ポインタではない
- 最初の受信パラメータは型、可変長パラメータは渡された型によって異なる
- スライス、マップ、チャネル用のメモリ領域割り当て専用
以下にいくつかの例を示します。
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 のチャネル