# #go
Вопрос:
Я не понимаю, почему приемник указателя не обновляется при назначении указателя на другой объект. Вот пример:
- Get-это экспортированный геттер,
- получить не сообщается,
Я хочу, чтобы Get() возвращал указатель на объект, содержащийся в карте указателей, индексированных строками.
Я не понимаю, почему приемник указателя метода get() не обновляется.
Я пробовал разные стратегии с почти одинаковым результатом каждый раз: разыменование, использование amp; вместо * в объявлениях переменных…
Идите на игровую площадку здесь: https://play.golang.org/p/zCLLvucbMjy
Есть идеи ? Спасибо!
package main
import (
"fmt"
)
type MyCollection map[string]*MyType
type MyType struct {
int
}
var collection MyCollection
func Get(key string) *MyType {
var rslt *MyType
// rslt := amp;MyType{}: gives almost the same result
rslt.get(key)
fmt.Println("rslt:", rslt) // Should print "rslt: amp;{2}"
return rslt
}
func (m *MyType) get(key string) {
m = collection[key]
// *m = collection[key] : cannot use collection[key] (type *MyType) as type MyType in assignment
fmt.Println("get m:", m) // Should print "get m: amp;{2}"
}
func main() {
collection = make(map[string]*MyType)
collection["1"] = amp;MyType{1}
collection["2"] = amp;MyType{2}
m := amp;MyType{1}
m = Get("2")
fmt.Println("final m", m) // Should print "final m: amp;{2}"
}
Комментарии:
1. play.golang.org/p/zhsC9PR3kwc — То, что вы пропустили, — это разыменование значения, считанного с карты, т. Е.
*m = *collection[key]
вместо*m = collection[key]
. И обратите внимание, что вы не можете сделать то же самое сvar rslt *MyType
insideGet
, потому что такоеrslt
естьnil
, а затем делать*m
внутриget
было бы паникой.2. Спасибо mkopriva, это действительно решает проблему ; Я все еще не понимаю, почему она компилируется и почему это так усложняется при разыменовании… когда я просто хочу манипулировать адресами :/ Спасибо, тхо !
3. «Я не понимаю, почему приемник указателя метода get() не обновляется». — Поскольку приемник является копией переменной вызывающего, без разыменования вы просто обновляете совершенно отдельную переменную. play.golang.org/p/um3JLjzSPrD (и обратите внимание, что каждый вызов получает свою собственную копию)
4. Спасибо за разъяснение, я каждый раз пропускал информацию о том, что получатель был копией. Не могли бы вы, пожалуйста, опубликовать это в качестве ответа, чтобы я мог закрыть вопрос ? Спасибо,
Ответ №1:
Вам нужно разыменовать приемник и присвоить ему значение разыменования с карты, т. е. *m = *collection[key]
.
Убедитесь, что перед вызовом rslt.get
переменная rslt
инициализирована, а не nil
, например rslt := amp;MyType{}
.
func Get(key string) *MyType {
rslt := amp;MyType{}
rslt.get(key)
fmt.Println("rslt:", rslt) // Should print "rslt: amp;{2}"
return rslt
}
func (m *MyType) get(key string) {
*m = *collection[key]
fmt.Println("get m:", m) // Should print "get m: amp;{2}"
}
https://play.golang.org/p/zhsC9PR3kwc
Обратите внимание, что причина m = collection[key]
недостаточна в том, что получатель всегда является копией переменной вызывающего абонента. И назначение непосредственно получателю просто обновит эту копию и не изменит переменную вызывающего абонента. Чтобы обновить данные, на которые указывают как получатель, так и переменная вызывающего абонента, необходимо разыменовать переменную. И обратите внимание, что каждый вызов получает свою собственную копию.