2016-07-18 2 views
5

Почему, когда мы ссылаемся на struct using (* structObj), golang, похоже, возвращает новую копию structObj, чем возвращает тот же адрес исходного structObj? Может быть какой-то неправильно понять мой на это, так что искать любезное разъяснение- это разыменование golang struct return new copy of struct?

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 

golang playground

ответ

2

Когда вы пишете

obj := *p 

Вы копируете значение структуры указана p (* различий p). Это похоже на:

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 

Now obj указывает на тот же объект, p. Они по-прежнему имеют разные адреса, но удерживают в них один и тот же адрес фактического объекта me.

+0

Есть ли способ получить такой же разыменованный указатель на p? как и в main() func, если мы добавляем структуру как срез, нам всегда придется разыгрывать ее внутри самого append, то есть res = append (res, * p). – ken

+0

Это не просто «создание» новой переменной, а назначение существующей переменной посредством разыменования копирует значение, например. '* a = * b' все еще копирует копии' * b' в '* a'. – JimB

+0

@jimB yap, есть ли способ избежать повторной копии? так как в основном операция просто должна иметь дело с одной и той же структурой p. – ken

6

Нет, «назначение» всегда создает копию в Go, включая назначение аргументов функции и метода. В заявлении obj := *p копируется значение *p - obj.

Если вы смените справку p.color = "purple" на (*p).color = "purple", вы получите тот же результат, потому что разыменование p сам не создает копию.

+0

на самом деле, исходя из c фона, это заставляет меня запутать. Спасибо, думаю, что оба ответа верны и до меня доходят примерно в то же время, поэтому выберите более подробную информацию, но повысьте это и на свой ответ! – ken

+0

'разыменование p сам не создает копию', это разъясняло мое замешательство, спасибо – stackoverflower