web-dev-qa-db-ja.com

構造体を逆参照すると、構造体の新しいコピーが返されますか?

(*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

遊び場に行く

12
ken

あなたが書くとき

obj := *p

p* dereferences p)が指すstructの値をコピーしています。これは次のようになります。

var obj me = *p

したがって、objme型の新しい変数であり、*pの値に初期化されます。これにより、objのメモリアドレスが異なります。

objmeタイプの場合、p*meタイプの場合に注意してください。しかし、それらは別個の値です。 objのフィールドの値を変更しても、p内のそのフィールドの値には影響しません(me構造体にフィールドとしての参照型がない場合(スライス)) 、マップまたはチャネル。 here および here を参照)。その効果をもたらしたい場合は、以下を使用します。

obj := p
// equivalent to: var obj *me = p

ここで、objpと同じオブジェクトを指します。それら自体にはまだ異なるアドレスがありますが、実際のmeオブジェクトの同じアドレスを内部に保持しています。

9
abhink

いいえ。「割り当て」は、関数とメソッドの引数への割り当てを含め、常にGoにコピーを作成します。ステートメントobj := *pは、*pの値をobjにコピーします。

ステートメントp.color = "purple"(*p).color = "purple"に変更すると、p自体を逆参照してもコピーが作成されないため、同じ出力が得られます。

13
JimB

tl; dr Goでの逆参照(*演算子を使用)はコピーを作成しません。ポインタが指す値を返します。

4
Michael Dorner