В коротком отрывке из Tour of Go говорится, что:
Методы с получателями указателей могут изменять значение, на которое указывает получатель [...]. Поскольку методам часто требуется модифицировать получателя, приемники указателей более распространены, чем приемники значений.
Почему r.b
отображается правильно, а r.a
вообще не изменяется?
Как уже говорилось в моем ответе ниже, ваш метод add()
является приемником значений. Поэтому он возьмет вашу инициализированную структуру (т.е. r
), скопирует ее, а затем соответствующим образом изменит. Поскольку вы инициализировали новую карту под r.b
в своей функции main()
, здесь копируется только ссылка на эту карту, но не вся карта. Поэтому манипуляция на карте работает, а на слайсе r.a
нет. Но почему r.a
совсем не меняется? Это связано с тем, что append()
, расположенный в методе add()
, хранит новый заголовок фрагмента под вашим свойством a
и указывает на другой раздел базового массива. В конце концов, ваш метод получателя значения add()
сделал копию r
, установил новый заголовок среза в свойстве a
и никогда не изменял исходную структуру r
, которая была определена в функции main()
, так как она была скопирована с помощью метода получателя значения. add()
.
В вашем случае метод add()
является так называемым методом получателя значений, который не может выполнять какие-либо манипуляции с определенной вами структурой r
, расположенной в функции main()
, напрямую, но копирует ее и впоследствии выполняет манипуляции. Поэтому вам нужно превратить ваш метод add()
в метод получателя указателя, как это:
func (r *R) add() {
r.a = append(r.a, 2)
r.b[2] = 2
}
Теперь метод берет фактическую ссылку на вашу структуру r
, которая инициируется в функции main()
, и соответствующим образом изменяет ее.
Как это могло бы работать без изменения метода add()
на приемник указателя?
Вам просто нужно будет вернуть скопированную структуру в метод add()
следующим образом:
package main
import (
"fmt"
)
func main() {
var r R
r.b = make(map[int]int)
fmt.Println(r.add()) // outputs {[2] map[2:2]}
}
type R struct {
a []int
b map[int]int
}
func (r R) add() R {
r.a = append(r.a, 2)
r.b[2] = 2
return r
}
person
bajro
schedule
27.11.2018
add
получает копию содержимого r, а не указатель на r. Внутриadd
r.a
заменяется обновленным значением среза, указывающим на другую память, включающую новый2
, но ничего не меняется в копииmain
r
. Когда операции среза, подобные этой do, работают, например, когдаRead
сохраняет данные в байтовый срез, это происходит потому, что две копии слайса уже указывают на одну и ту же память, а операция изменения слайса просто изменила уже имеющуюся. -Общая память. Это введение в работу срезов может помочь: blog.golang.org/slices - person twotwotwo   schedule 28.11.2018