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

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 構文は機能します 大丈夫 ではなく *int の場合 *int64編集: いいえ、そうではありません。申し訳ありません。

編集:

どうやら私の質問は曖昧すぎるようです。文字通り述べるa *int64。これはコンストラクタ内で使用したり、リテラル構造体の値を記述したり、他の関数の引数として使用したりすることもできます。ただし、ヘルパー関数や別の型の使用は、私が探している解決策ではありません。

ベストアンサー1

Go言語仕様(アドレス演算子)は数値定数のアドレスを取ることはできません(未入力また、入力した絶え間ない)。

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

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

0) 一般的なソリューション (Go 1.18 から)

Go 1.18ではジェネリックが追加されました。つまり、Ptr()渡した値へのポインタを返す単一のジェネリック関数を作成できるということです。標準ライブラリに追加されることを期待しています。それまでは、github.com/icza/goggog.Ptr()機能(開示:私は著者です)。

次のようになります:

func Ptr[T any](v T) *T {
    return &v
}

テスト中:

i := Ptr(2)
log.Printf("%T %v", i, *i)

s := Ptr("abc")
log.Printf("%T %v", s, *s)

x := Ptr[any](nil)
log.Printf("%T %v", x, *x)

出力されます(遊び場に行く):

2009/11/10 23:00:00 *int 2
2009/11/10 23:00:00 *string abc
2009/11/10 23:00:00 *interface {} <nil>

その他のオプション(Go 1.18以前)(すべて試してください)遊び場に行く):

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) 1行の匿名関数で

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,
}

おすすめ記事