このような場合を処理する最もクリーンな方法は次のとおりです。
func a() string {
/* doesn't matter */
}
b *string = &a()
これにより、次のエラーが生成されます。
a() のアドレスを取ることはできません
私の理解では、アドレスが取得された場合、Go は自動的にローカル変数をヒープに昇格させます。ここで、戻り値のアドレスが取得されることは明らかです。これを処理するための慣用的な方法は何ですか?
アドレス演算子は、変数などの「ホーム」を持つものへのポインターを返します。コード内の式の値は「ホームレス」です。*string が本当に必要な場合は、次の 2 つの手順で行う必要があります。
tmp := a(); b := &tmp
*string には完全に有効な使用例がありますが、多くの場合、それらを使用するのは間違いであることに注意してください。In Gostring
は値型ですが、受け渡すのに安価な型 (ポインターと int) です。文字列の値は不変で*string
あり、文字列値ではなく「ホーム」が指す場所を変更するため、ほとんどの場合*string
、まったく必要ありません。
Go言語仕様の関連セクションを参照してください。&
以下でのみ使用できます。
あなたが持っているものはそのどちらでもないので、うまくいきません。
できたとしても、それが何を意味するのかさえわかりません。関数呼び出しの結果のアドレスを取得しますか? 通常、何かのポインターを誰かに渡します。これは、誰かが指し示すものに割り当てて、元の変数の変更を確認できるようにするためです。ただし、関数呼び出しの結果は一時的なものです。最初に何かに割り当てない限り、他の誰もそれを「見る」ことはありません。
ポインターを作成する目的がnew()
、複合リテラルのアドレスと同様に、またはそのアドレスを取得する動的な有効期間を持つものを作成することである場合、関数呼び出しの結果を変数に割り当てて、そのアドレスを取得できます。
最後に、Go で任意の式のアドレスを取得できるようにすることを提案しています。たとえば、次のようになります。
i,j := 1,2
var p *int = &(i+j)
println(*p)
現在の Go コンパイラは次のエラーを出力します。cannot take the address of i + j
私の意見では、プログラマーが任意の式のアドレスを取得できるようにします。
コンパイラと仕様を複雑にして、利益をほとんど得られないようにすることは、逆効果に思えます。
私は最近、似たようなことについて結び目で縛られました。
あなたの例で最初に文字列について話すのは気を散らすものです。代わりに構造体を使用して、次のように書き直してください。
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 {}は、構造体または構造体へのポインターにすることができます。同じコピーの問題が発生します。
a()
スタック上にあるため、変数を指していません。スタックを指すことはできません (なぜそうするのですか?)。
必要に応じてそれを行うことができます
va := a()
b := &va
しかし、あなたが本当に達成したいことはやや不明確です。