Golang | Назначение указателя приемнику указателя не работает

# #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 inside Get , потому что такое 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] недостаточна в том, что получатель всегда является копией переменной вызывающего абонента. И назначение непосредственно получателю просто обновит эту копию и не изменит переменную вызывающего абонента. Чтобы обновить данные, на которые указывают как получатель, так и переменная вызывающего абонента, необходимо разыменовать переменную. И обратите внимание, что каждый вызов получает свою собственную копию.

https://play.golang.org/p/um3JLjzSPrD