*int64
フィールドを持つ構造体型があります。
type SomeType struct {
SomeField *int64
}
私のコードのある時点で、このリテラルを宣言したいと思います(たとえば、値が0であるべきだとわかっているとき、または0を指しているとき、あなたは私の意味を知っています)
instance := SomeType{
SomeField: &0,
}
...ただし、これは機能しません
./main.go:xx: cannot use &0 (type *int) as type *int64 in field value
だから私はこれを試して
instance := SomeType{
SomeField: &int64(0),
}
...しかし、これも機能しません
./main.go:xx: cannot take the address of int64(0)
どうすればいいですか?私が思いつく唯一の解決策は、プレースホルダー変数を使用することです
var placeholder int64
placeholder = 0
instance := SomeType{
SomeField: &placeholder,
}
注: 編集:いいえ、しません。これにつきましては申し訳ございません。&0
構文は、*int64
ではなく* intの場合にfineが機能します。
編集:
明らかに、私の質問にはあいまいさが多すぎました。 literally state a *int64
への方法を探しています。これは、コンストラクタ内で使用したり、リテラル構造体の値を記述したり、他の関数の引数として使用することもできます。しかし、ヘルパー関数または別のタイプの使用は、私が探しているソリューションではありません。
Go言語仕様( アドレス演算子 )では、数値定数(untypedまたはtypedconstant)。
オペランドは、addressable、つまり、変数、ポインター間接指定、またはスライスのインデックス付け操作でなければなりません。または、アドレス可能な構造体オペランドのフィールドセレクタ。または、アドレス指定可能な配列の配列インデックス付け操作。アドレス可能性の要件の例外として、
x
[&x
の式内]は、(おそらく括弧で囲まれた) 複合リテラル である場合もあります。
これが許可されない理由については、関連する質問を参照してください: goで定数のアドレスを検索 。同様の質問(アドレスを取得することも同様に許可されていません): Goでの操作の結果への参照を保存するにはどうすればよいですか
あなたのオプション( Go Playground ですべて試してください):
new()
を使用単に組み込みの new()
関数を使用して、新しいゼロ値のint64
を割り当て、そのアドレスを取得できます。
instance := SomeType{
SomeField: new(int64),
}
ただし、これは、任意のタイプのゼロ値へのポインターを割り当てて取得するためにのみ使用できることに注意してください。
非ゼロ要素に最も簡単で推奨されるのは、アドレスを取得できるヘルパー変数を使用することです。
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
または、これが何度も必要な場合は、*int64
を割り当てて返すヘルパー関数を作成できます。
func create(x int64) *int64 {
return &x
}
そしてそれを使用して:
instance3 := SomeType{
SomeField: create(3),
}
実際には何も割り当てなかったことに注意してください。Goコンパイラは、関数の引数のアドレスを返したときに割り当てました。 Goコンパイラーはエスケープ解析を実行し、関数をエスケープする可能性がある場合は、ローカル変数を(スタックではなく)ヒープに割り当てます。詳細については、「 Go関数でローカル配列のスライスを返すのは安全ですか? 」を参照してください
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
または(より短い)代替として:
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
*SomeField
を0
以外にする場合は、アドレス可能なものが必要です。
あなたはまだそれを行うことができますが、それはいです:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5
ここで起こるのは、1つの要素([]int64
)を持つリテラルで5
スライスが作成されることです。そして、インデックスが付けられ(0番目の要素)、0番目の要素のアドレスが取得されます。バックグラウンドでは、[1]int64
の配列も割り当てられ、スライスのバッキング配列として使用されます。そのため、ここには定型文がたくさんあります。
アドレス可能性要件の例外を調べてみましょう。
アドレス可能性の要件の例外として、
x
[&x
の式内]は、(おそらく括弧で囲まれた) 複合リテラル である場合もあります。
これは、複合リテラルのアドレスを取得することを意味します。構造体リテラルは大丈夫です。そうする場合、構造体の値が割り当てられ、ポインタが取得されます。しかし、そうであれば、別の要件が利用可能になります: "アドレス指定可能な構造体オペランドのフィールドセレクター"したがって、構造体リテラルにint64
型のフィールドが含まれている場合、そのフィールドのアドレスも取得できます。
このオプションの動作を見てみましょう。このラッパー構造タイプを使用します。
type intwrapper struct {
x int64
}
そして今、私たちができること:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
これに注意してください
&(&intwrapper{6}).x
以下を意味します。
& ( (&intwrapper{6}).x )
ただし、アドレス演算子&
が selector expression の結果に適用されるため、「外部」括弧を省略できます。
また、バックグラウンドで以下が発生することに注意してください(これも有効な構文です)。
&(*(&intwrapper{6})).x
原則はケース#6と同じですが、匿名の構造リテラルも使用できるため、ヘルパー/ラッパー構造タイプの定義は必要ありません。
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}
以下のコードでは、整数を受け入れ、整数のアドレスを保持するポインター値を返す関数fを使用します。この方法を使用すると、上記の問題を簡単に解決できます。
type myStr struct {
url *int64
}
func main() {
f := func(s int64) *int64 {
return &s
}
myStr{
url: f(12345),
}
}