web-dev-qa-db-ja.com

Goでリテラル* int64を実行するにはどうすればよいですか?

*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への方法を探しています。これは、コンストラクタ内で使用したり、リテラル構造体の値を記述したり、他の関数の引数として使用することもできます。しかし、ヘルパー関数または別のタイプの使用は、私が探しているソリューションではありません。

75
ThisGuy

Go言語仕様( アドレス演算子 )では、数値定数(untypedまたはtypedconstant)。

オペランドは、addressable、つまり、変数、ポインター間接指定、またはスライスのインデックス付け操作でなければなりません。または、アドレス可能な構造体オペランドのフィールドセレクタ。または、アドレス指定可能な配列の配列インデックス付け操作。アドレス可能性の要件の例外として、x [&xの式内]は、(おそらく括弧で囲まれた) 複合リテラル である場合もあります。

これが許可されない理由については、関連する質問を参照してください: goで定数のアドレスを検索 。同様の質問(アドレスを取得することも同様に許可されていません): Goでの操作の結果への参照を保存するにはどうすればよいですか

あなたのオプション( Go Playground ですべて試してください):

1)new()を使用

単に組み込みの new() 関数を使用して、新しいゼロ値のint64を割り当て、そのアドレスを取得できます。

instance := SomeType{
    SomeField: new(int64),
}

ただし、これは、任意のタイプのゼロ値へのポインターを割り当てて取得するためにのみ使用できることに注意してください。

2)ヘルパー変数付き

非ゼロ要素に最も簡単で推奨されるのは、アドレスを取得できるヘルパー変数を使用することです。

helper := int64(2)
instance2 := SomeType{
    SomeField: &helper,
}

3)ヘルパー機能付き

または、これが何度も必要な場合は、*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)スライスリテラルを使用して、インデックスを作成し、アドレスを取得する

*SomeField0以外にする場合は、アドレス可能なものが必要です。

あなたはまだそれを行うことができますが、それはいです:

instance5 := SomeType{
    SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5

ここで起こるのは、1つの要素([]int64)を持つリテラルで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 )

ただし、アドレス演算子&selector expression の結果に適用されるため、「外部」括弧を省略できます。

また、バックグラウンドで以下が発生することに注意してください(これも有効な構文です)。

&(*(&intwrapper{6})).x

7)ヘルパー匿名構造リテラルを使用

原則はケース#6と同じですが、匿名の構造リテラルも使用できるため、ヘルパー/ラッパー構造タイプの定義は必要ありません。

instance7 := SomeType{
    SomeField: &(&struct{ x int64 }{7}).x,
}
161
icza

Int64変数のアドレスを返す関数を使用すると、問題が解決します。

以下のコードでは、整数を受け入れ、整数のアドレスを保持するポインター値を返す関数fを使用します。この方法を使用すると、上記の問題を簡単に解決できます。

 type myStr struct {
        url *int64
    }

    func main() {

        f := func(s int64) *int64 {
            return &s
        }
        myStr{
            url: f(12345),
        }
    }
3
ASHWIN RAJEEV