Dictionary 无法获取映射元素的地址

Dictionary 无法获取映射元素的地址,dictionary,pointers,go,methods,Dictionary,Pointers,Go,Methods,我想知道原因 x:= odsMap[segRef] x.GetValue("@OriginDestinationKey") 有效,但这并不: odsMap[segRef].GetValue("@OriginDestinationKey") ? 最后一个代码段打印以下错误: cannot call pointer method on odsMap[segRef]go cannot take the address of odsMap[segRef] 这些错误发生在编译时(而不是运行时)。所以

我想知道原因

x:= odsMap[segRef]
x.GetValue("@OriginDestinationKey")
有效,但这并不:

odsMap[segRef].GetValue("@OriginDestinationKey")
?

最后一个代码段打印以下错误:

cannot call pointer method on odsMap[segRef]go
cannot take the address of odsMap[segRef]
这些错误发生在编译时(而不是运行时)。所以,我的主要问题是为什么我需要一个中间变量
x
来访问函数

关于变量的类型,
odsMap
是一个
map[string]
XMLElement,
segRef
是一个字符串


谢谢。

映射索引表达式是不可寻址的,因为映射的内部可能会在添加新条目时发生变化,因此规范故意不允许获取其地址(这为映射实现提供了更大的自由度)

这意味着如果在映射中存储非指针,并且希望调用具有指针接收器的存储值的方法,则需要获取非指针值的地址(用作接收器),但由于映射索引表达式不可寻址,因此会导致编译时错误

解决方法是在映射中存储指针值,因此不需要获取索引表达式的地址,因为它已经是指针了。答案中可以看到一个例子:如果我们有这种类型:

type My int

func (m *My) Str() string { return strconv.Itoa(int(*m)) }
这给出了有问题的编译时错误:

m := map[int]My{0: My(12)}
m[0].Str() // Error!
但这是可行的:

m := map[int]*My{}
my := My(12)
m[0] = &my // Store a pointer in the map

m[0].Str() // You can call it, no need to take the address of m[0]
           // as it is already a pointer
另一种选择是将其分配给一个可以获取其地址的局部变量,并对该变量调用指针方法。但必须注意,如果该方法具有指针接收器,它可能会修改指向的对象或其组件(例如,结构的字段),这不会反映在映射中存储的值中。如果沿着此路径,可能需要将值重新分配给映射中的键,以获得更新的值

总而言之,如果您有一个值的类型具有指针接收器的方法,那么最好将它(存储、传递)用作指针,而不是非指针值

见相关问题:

是正确的

以下示例说明“值接收器”与“指针接收器”如何与“指针映射”与“值映射”交互:


请提供一个。为了完整性:能否在问题中添加“odsMap”变量的声明?如果方法使用指针更新局部值,则分配给局部变量可能还需要在映射中重新分配该值。@bereal是的,您是对的。将其赋给局部变量将创建存储在映射中的值的副本。感谢@icza Understanding!!:)@icza:“当一个新条目被添加到地图中时,地图的内部可能会发生变化。”当一个条目被添加或删除时。感谢@LeGEC:)
package main

import (
    "fmt"
)

// a simple type, with two methods : one with a value receiver, one with a pointer receiver
type Item struct {
    name string
}

func (i Item) GetNameByValue() string {
    return i.name
}

func (i *Item) GetNameByRef() string {
    return i.name
}

func main() {
    {
        // in this map, we store *pointers* to Item values
        mapByRef := make(map[int]*Item)

        mapByRef[0] = &Item{"I am stored as a pointer"}

        // GetNameByRef will work on a *Item : "mapByRef[0]" is already a pointer
        fmt.Println("GetByRef   :", mapByRef[0].GetNameByRef())

        // GetNameByValue will work on a *Item :   go automatically turns this into '(*mapByRef[0]).GetNameByValue()', and this is valid
        fmt.Println("GetByValue :", mapByRef[0].GetNameByValue())
    }

    {
        // in this map, we store Item values (no pointers)
        mapByValue := make(map[int]Item)

        mapByValue[0] = Item{"I am stored as a value"}

        // GetNameByValue will work on a Item :  "mapByValue[0]" has the right type
        fmt.Println("GetByValue :", mapByValue[0].GetNameByValue())

        // GetNameByRef will not work :  go tries to turn this into :  (&mapByValue[0]).GetNameByRef(),
        // and go refuses to let you take the address of a value inside a map

        // fmt.Println("GetByRef   :", mapByValue[0].GetNameByRef())

        // compiler error :
        //   ./prog.go:47:46: cannot call pointer method on mapByValue[0]
        //   ./prog.go:47:46: cannot take the address of mapByValue[0]

        // you will need some way to copy the value before taking its address :
        item := mapByValue[0]
        fmt.Println("item.GetByRef    :", item.GetNameByRef())
        // same as :
        fmt.Println("(&item).GetByRef :", (&item).GetNameByRef())
    }
}

// Output :
//
// GetByRef   : I am stored as a pointer
// GetByValue : I am stored as a pointer
// GetByValue : I am stored as a value
// item.GetByRef    : I am stored as a value
// (&item).GetByRef : I am stored as a value