(*structObj)
を使用して構造体を参照するときに、Goが元のstructObj
の同じアドレスを返すのではなく、structObj
の新しいコピーを返すように見えるのはなぜですか?これは私の誤解かもしれないので、説明を求めます
package main
import (
"fmt"
)
type me struct {
color string
total int
}
func study() *me {
p := me{}
p.color = "tomato"
fmt.Printf("%p\n", &p.color)
return &p
}
func main() {
p := study()
fmt.Printf("&p.color = %p\n", &p.color)
obj := *p
fmt.Printf("&obj.color = %p\n", &obj.color)
fmt.Printf("obj = %+v\n", obj)
p.color = "purple"
fmt.Printf("p.color = %p\n", &p.color)
fmt.Printf("p = %+v\n", p)
fmt.Printf("obj = %+v\n", obj)
obj2 := *p
fmt.Printf("obj2 = %+v\n", obj2)
}
出力
0x10434120
&p.color = 0x10434120
&obj.color = 0x10434140 //different than &p.color!
obj = {color:tomato total:0}
p.color = 0x10434120
p = &{color:purple total:0}
obj = {color:tomato total:0}
obj2 = {color:purple total:0} // we get purple now when dereference again
あなたが書くとき
obj := *p
p
(*
dereferences p
)が指すstructの値をコピーしています。これは次のようになります。
var obj me = *p
したがって、obj
はme
型の新しい変数であり、*p
の値に初期化されます。これにより、obj
のメモリアドレスが異なります。
obj
はme
タイプの場合、p
は*me
タイプの場合に注意してください。しかし、それらは別個の値です。 obj
のフィールドの値を変更しても、p
内のそのフィールドの値には影響しません(me
構造体にフィールドとしての参照型がない場合(スライス)) 、マップまたはチャネル。 here および here を参照)。その効果をもたらしたい場合は、以下を使用します。
obj := p
// equivalent to: var obj *me = p
ここで、obj
はp
と同じオブジェクトを指します。それら自体にはまだ異なるアドレスがありますが、実際のme
オブジェクトの同じアドレスを内部に保持しています。
いいえ。「割り当て」は、関数とメソッドの引数への割り当てを含め、常にGoにコピーを作成します。ステートメントobj := *p
は、*p
の値をobj
にコピーします。
ステートメントp.color = "purple"
を(*p).color = "purple"
に変更すると、p
自体を逆参照してもコピーが作成されないため、同じ出力が得られます。
tl; dr Goでの逆参照(*
演算子を使用)はコピーを作成しません。ポインタが指す値を返します。