В Go использование сеттера для типа структуры не работает, как ожидалось - PullRequest
7 голосов
/ 25 июня 2011

Использование функции сеттера для структуры, но не работает, как ожидалось:

package main

import "fmt"

type T struct { Val string }

// this setter seems not to work
func (t T) SetVal( s string ) {
        t.Val = s
}

// this setter, using ptr to T, seems to work ok
func (t *T) SetVal2( s string ) {
        (*t).Val = s
}

func main() {
        v := T{"abc"}
        fmt.Println( v )        // prints {abc}
        v.SetVal("pdq")
        fmt.Println( v )        // prints {abc}, was expecting {pdq}!
        v.SetVal2("xyz")
        fmt.Println( v )        // prints {xyz}!
}

Мне не хватает фундаментального понимания - почему SetVal не работает?

поведениеаналогично установке значений в reflect, которая работает только в том случае, если указатель указывается на объект, а не на сам объект

Ответы [ 2 ]

16 голосов
/ 25 июня 2011

Вот фундаментальное понимание, которого вам не хватает: когда структура передается функции в качестве указателя, функция может изменить исходную структуру, потому что она имеет указатель на нее.Однако, когда структура передается функции через ее значение, тогда фактически создается НОВАЯ копия структуры только для этого вызова функции, и любые изменения этой новой копии структуры не влияют на исходную структуру.

Вы можете доказать, что так оно и работает, распечатав фактические адреса рассматриваемых структур:

package main

import "fmt"

type T struct { Val string }

func (t T) SetVal( s string ) {
        fmt.Printf("Address of copy is %p\n", &t);
}

func (t *T) SetVal2( s string ) {
        fmt.Printf("Pointer argument is %p\n", t);
}

func main() {
        v := T{"abc"}
        fmt.Printf("Address of v is %p\n", &v);
        v.SetVal("pdq")
        v.SetVal2("xyz")
}

Приведенный выше код приводит к таким выводам, когда я запускаю его на игровой площадке Go:

Address of v is 0xf840001290
Address of copy is 0xf8400013e0
Pointer argument is 0xf840001290

Обратите внимание, как распечатаны первый и третий указатели, что означает, что они имеют одинаковую структуру.Но второй указатель отличается тем, что он является копией.

Кстати, это похоже на то, как работает структура C / параметры функции.

1 голос
/ 10 января 2018

Это разница между вызовом по значению и вызовом по ссылке. Если вы из C ++, то знайте, что в C ++ тоже самое. И если вы из Java-фона, то помните, что все ссылки на объекты - это просто указатели на объекты на самом деле ... (то есть, когда мы делаем Node node = new Node (); .. узел содержит адрес нового узла) объект создан). Поэтому любой метод объекта (узла) фактически вызывается по ссылке (поскольку сам узел является указателем) .. поэтому он сводится к тому же примеру, что и выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...