Go言語仕様(アドレス演算子)では、数値定数(型なし定数や型付き定数ではない)のアドレスを取得できません。
オペランドはアドレス指定可能である必要があります。つまり、変数、ポインターの間接指定、またはスライスのインデックス付け操作のいずれかです。または、アドレス可能な構造体オペランドのフィールドセレクタ。または、アドレス可能な配列の配列インデックス操作。アドレッシング要件の例外として、x
[の式の中の&x
]は(括弧で囲まれた)複合リテラルでもある場合があります。
これが許可されない理由については、関連する質問を参照してください:goで定数のアドレスを検索してください。同様の質問(同様にそのアドレスを取得することもできません):Goでの操作の結果への参照をどのように保存できますか?
オプション(Go Playgroundですべてお試しください):
1)あり new()
組み込みnew()
関数を使用して、新しいゼロ値を割り当て、int64
そのアドレスを取得するだけです。
instance := SomeType{
SomeField: new(int64),
}
ただし、これは、任意の型のゼロ値へのポインターを割り当てて取得するためにのみ使用できることに注意してください。
2)ヘルパー変数を使用
ゼロ以外の要素に対して最も簡単で推奨されるのは、アドレスを取得できるヘルパー変数を使用することです。
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
3)ヘルパー機能付き
注:ゼロ以外の値へのポインターを取得するヘルパー関数は、github.com/icza/gox
ライブラリーのgox
パッケージで使用できるため、必要なすべてのプロジェクトにこれらを追加する必要はありません。
または、これが何度も必要な場合は、を割り当てて返すヘルパー関数を作成できます*int64
。
func create(x int64) *int64 {
return &x
}
そしてそれを使う:
instance3 := SomeType{
SomeField: create(3),
}
実際には何も割り当てていないことに注意してください。Goコンパイラーは、関数の引数のアドレスを返すときにそれを行いました。Goコンパイラーは、エスケープ分析を実行し、関数をエスケープする可能性がある場合は、ローカル変数を(スタックではなく)ヒープに割り当てます。詳細については、Go関数でローカル配列のスライスを安全に返すことを参照してください。
4)ワンライナー無名関数を使用
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
または(短い)代替として:
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
5)スライスリテラル、インデックス付け、アドレス指定
*SomeField
以外の人になりたい場合は0
、アドレス可能な何かが必要です。
あなたはまだそれを行うことができますが、それは醜いです:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5
ここで発生するのは、[]int64
1つの要素(5
)を持つリテラルでスライスが作成されることです。そして、インデックスが付けられ(0番目の要素)、0番目の要素のアドレスが取得されます。バックグラウンドでは、の配列[1]int64
も割り当てられ、スライスのバッキング配列として使用されます。ここには定型文がたくさんあります。
6)ヘルパー構造体リテラルを使用
アドレス指定要件の例外を調べてみましょう。
アドレッシング要件の例外として、x
[の式の中の&x
]は(括弧で囲まれた)複合リテラルでもある場合があります。
つまり、構造体リテラルなどの複合リテラルのアドレスを取得しても問題ありません。そうする場合、構造体の値が割り当てられ、それへのポインタが取得されます。しかし、そうであれば、「アドレス指定可能な構造体オペランドのフィールドセレクター」という別の要件が利用可能になります。したがって、構造体リテラルにタイプのフィールドが含まれている場合はint64
、そのフィールドのアドレスも取得できます。
このオプションの動作を見てみましょう。このラッパー構造体タイプを使用します。
type intwrapper struct {
x int64
}
そして今、私たちはできる:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
これは
&(&intwrapper{6}).x
以下を意味します:
& ( (&intwrapper{6}).x )
ただし&
、セレクター式の結果にアドレス演算子が適用されるため、「外側」の括弧は省略できます。
また、バックグラウンドで次のことが発生することにも注意してください(これも有効な構文です)。
&(*(&intwrapper{6})).x
7)ヘルパーの匿名構造体リテラルを使用
原則はケース#6と同じですが、匿名の構造体リテラルを使用することもできるため、ヘルパー/ラッパーの構造体型定義は必要ありません。
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}