Возвращает ли разыменование структуры новую копию структуры?
Почему, когда мы ссылаемся на struct, используя (*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
Иди на площадку
Ответы
Ответ 1
Когда вы пишете
obj := *p
Вы копируете значение структуры, на которое указывает p
(*
разыменовывает p
). Это похоже на:
var obj me = *p
Итак, obj
- это новая переменная типа me
, которая инициализируется значением *p
. Это приводит к тому, что obj
имеет другой адрес памяти.
Обратите внимание, что obj
имеет тип me
, а p
имеет тип *me
. Но это отдельные ценности. Изменение значения поля obj
не повлияет на значение этого поля в p
(если только структура me
не имеет ссылочного типа в качестве поля, то есть среза, карты или каналов. См. здесь и здесь.). Если вы хотите добиться такого эффекта, используйте:
obj := p
// equivalent to: var obj *me = p
Теперь obj
указывает на тот же объект, что и p
. Они по-прежнему имеют разные адреса, но содержат в себе один и тот же адрес фактического объекта me
.
Ответ 2
Нет, "назначение" всегда создает копию в Go, включая назначение аргументов функции и метода. Оператор obj := *p
копирует значение *p
в obj
.
Если вы измените оператор p.color = "purple"
на (*p).color = "purple"
, вы получите тот же результат, потому что разыменование p
сам не создает копию.
Ответ 3
tl;dr Разыменование (с помощью оператора *
) в Go не делает копию. Возвращает значение, на которое указывает указатель.