48

このような場合を処理する最もクリーンな方法は次のとおりです。

func a() string {
    /* doesn't matter */
}

b *string = &a()

これにより、次のエラーが生成されます。

a() のアドレスを取ることはできません

私の理解では、アドレスが取得された場合、Go は自動的にローカル変数をヒープに昇格させます。ここで、戻り値のアドレスが取得されることは明らかです。これを処理するための慣用的な方法は何ですか?

4

9 に答える 9

52

アドレス演算子は、変数などの「ホーム」を持つものへのポインターを返します。コード内の式の値は「ホームレス」です。*string が本当に必要な場合は、次の 2 つの手順で行う必要があります。

tmp := a(); b := &tmp

*string には完全に有効な使用例がありますが、多くの場合、それらを使用するのは間違いであることに注意してください。In Gostringは値型ですが、受け渡すのに安価な型 (ポインターと int) です。文字列のは不変で*stringあり、文字列値ではなく「ホーム」が指す場所を変更するため、ほとんどの場合*string、まったく必要ありません。

于 2012-05-10T14:23:52.217 に答える
15

Go言語仕様の関連セクションを参照してください。&以下でのみ使用できます。

  1. アドレス可能なもの: 変数、ポインター間接化、スライス インデックス操作、アドレス指定可能な構造体のフィールド セレクター、アドレス指定可能な配列の配列インデックス操作。また
  2. 複合リテラル

あなたが持っているものはそのどちらでもないので、うまくいきません。

できたとしても、それが何を意味するのかさえわかりません。関数呼び出しの結果のアドレスを取得しますか? 通常、何かのポインターを誰かに渡します。これは、誰かが指し示すものに割り当てて、元の変数の変更を確認できるようにするためです。ただし、関数呼び出しの結果は一時的なものです。最初に何かに割り当てない限り、他の誰もそれを「見る」ことはありません。

ポインターを作成する目的がnew()、複合リテラルのアドレスと同様に、またはそのアドレスを取得する動的な有効期間を持つものを作成することである場合、関数呼び出しの結果を変数に割り当てて、そのアドレスを取得できます。

于 2012-05-10T22:48:48.203 に答える
5

最後に、Go で任意の式のアドレスを取得できるようにすることを提案しています。たとえば、次のようになります。

i,j := 1,2
var p *int = &(i+j)
println(*p)

現在の Go コンパイラは次のエラーを出力します。cannot take the address of i + j

私の意見では、プログラマーが任意の式のアドレスを取得できるようにします。

  • あまり役に立たないようです (つまり、実際の G​​o プログラムで発生する可能性は非常に低いようです)。
  • コンパイラと言語仕様が複雑になります。

コンパイラと仕様を複雑にして、利益をほとんど得られないようにすることは、逆効果に思えます。

于 2012-05-11T11:18:57.940 に答える
1

私は最近、似たようなことについて結び目で縛られました。

あなたの例で最初に文字列について話すのは気を散らすものです。代わりに構造体を使用して、次のように書き直してください。

func a() MyStruct {
    /* doesn't matter */
}

var b *MyStruct = &a()

a()のアドレスを取得できないため、これはコンパイルされません。だからこれを行う:

func a() MyStruct {
    /* doesn't matter */
}

tmpA := a()
var b *MyStruct = &tmpA

これはコンパイルされますが、スタックにMyStructを返し、MyStructを格納するのに十分なスペースをヒープに割り当ててから、コンテンツをスタックからヒープにコピーしました。これを避けたい場合は、次のように記述してください。

func a2() *MyStruct {
  /* doesn't matter as long as MyStruct is created on the heap (e.g. use 'new') */
}

var a *MyStruct = a2()

通常、コピーは安価ですが、これらの構造体は大きい場合があります。さらに悪いことに、構造体を変更して「スティック」にしたい場合は、コピーしてからコピーを変更することはできません。

とにかく、returnタイプのinterface {}を使用していると、さらに楽しくなります。interface {}は、構造体または構造体へのポインターにすることができます。同じコピーの問題が発生します。

于 2012-05-11T12:25:21.190 に答える
0

a()スタック上にあるため、変数を指していません。スタックを指すことはできません (なぜそうするのですか?)。

必要に応じてそれを行うことができます

va := a()
b := &va

しかし、あなたが本当に達成したいことはやや不明確です。

于 2012-05-10T14:23:36.710 に答える