我想知道为什么
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
是一个字符串。
谢谢。
Map 索引表达式不可寻址,因为当向其添加新条目时,map 的内部可能会发生变化,因此规范有意不允许获取其地址(这为 map 实现提供了更大的自由度)。
这意味着如果您在映射中存储非指针,并且您想要调用具有指针接收器的存储值的方法,则需要获取非指针值的地址(用作接收器),但由于映射索引表达式不可寻址,因此会导致编译时错误。
一种解决方法是将指针值存储在映射中,因此无需获取索引表达式的地址,因为它已经是一个指针。在这个答案中可以看到这样的一个例子:Go 的构造函数为什么要返回地址? 如果我们有这种类型:
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
另一种选择是将其分配给可以获取其地址的局部变量,并在其上调用指针方法。但必须小心,因为如果该方法具有指针接收器,它可能会修改指向的对象或其组件(例如结构的字段),这不会反映在映射中存储的值中。如果沿着这条路走下去,您可能必须将值重新分配给地图中的键才能获得更新后的值。
总而言之,如果你有一个值,其类型具有带指针接收器的方法,你最好将它(存储、传递)用作指针而不是非指针值。
查看相关问题:
@icza的回答是正确的。
这里有一个例子来说明“值接收者”与“指针接收者”如何与“指针映射”与“值映射”交互:
https://play.golang.org/p/JVp6DirgPkU
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