Получатель значения struct на языке программирования Go? - PullRequest
0 голосов
/ 28 ноября 2018

Может кто-нибудь объяснить мне, почему вывод ra пустой, поскольку я добавил значение 2 в список?

package main

import (
    "fmt"
)

func main() {
    var r R
    r.b = make(map[int]int)

    r.add()
    fmt.Println(r) // outputs {[] map[2:2]}
}

type R struct {
    a []int
    b map[int]int
}

func (r R) add()  {
    r.a = append(r.a, 2)
    r.b[2] = 2
}

1 Ответ

0 голосов
/ 28 ноября 2018

Краткий отрывок из 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
}
...