Go语言:如何修改结构体嵌套map中的Vertex?解决地址获取报错
解决Go中Map值类型无法调用指针接收者方法的问题
这个问题的核心在于Go语言中map值的访问特性——当你从map[string]Vertex中取出一个Vertex值时,得到的是原值的副本,而不是原值本身。临时的副本值是不可寻址的,这就是为什么你会遇到cannot call pointer method on g.vertexes[person]和cannot take the address of g.vertexes[person]这两个错误。
下面给你两种可行的解决方案,你可以根据自己的需求选择:
方案一:将Map的Value类型改为指针(推荐)
最直接的解决方式是把Graph结构体中vertexes的类型从map[string]Vertex改成map[string]*Vertex,这样存储的是Vertex的指针而非值。当你从map中取出元素时,得到的是指向原Vertex对象的指针,可以直接调用指针接收者方法:
// 修改结构体定义 type Graph struct { vertexes map[string]*Vertex // 改为指针类型 } // 初始化Graph时创建指针类型的Vertex func main() { people := []string{"dave", "tim", "jack"} g := Graph{make(map[string]*Vertex)} // 对应修改map的类型 for _, p := range people { // 创建Vertex的指针并放入map g.vertexes[p] = &Vertex{p, make(map[string]decimal.Decimal)} } UpdateGraph("dave", "jack", "0.3434555444433444", &g) } // UpdateGraph函数不需要修改,直接调用即可 func UpdateGraph(person, friend, strength string, g *Graph) decimal.Decimal { nicestrength, _ := decimal.NewFromString(strength) g.vertexes[person].Edge(friend, nicestrength) // 指针直接调用方法 return nicestrength }
这种方式的优势在于逻辑清晰,后续对Vertex的修改都是直接作用在原对象上,不会有副本带来的意外问题。
方案二:先取出副本修改,再存回Map
如果你不想修改map的类型,可以先把Vertex的副本取出来,通过取副本的地址调用指针方法,再将修改后的副本存回map:
func UpdateGraph(person, friend, strength string, g *Graph) decimal.Decimal { nicestrength, _ := decimal.NewFromString(strength) // 1. 取出map中的Vertex副本 v := g.vertexes[person] // 2. 取副本的地址,调用指针接收者方法 (&v).Edge(friend, nicestrength) // 3. 将修改后的副本存回map(注:因为edges是引用类型,这里即使不存回,原map中Vertex的edges也会被修改,但存回是更严谨的做法,避免后续修改其他字段时出现问题) g.vertexes[person] = v return nicestrength }
另外补充一种思路:如果你的Edge方法只需要修改edges字段(而edges是引用类型的map),也可以把Edge方法改成值接收者,这样直接调用副本的方法也能修改底层的map:
// 修改为值接收者方法 func (v Vertex) Edge(t string, w decimal.Decimal) { v.edges[t] = w } // 此时UpdateGraph中的调用可以直接执行 g.vertexes[person].Edge(friend, nicestrength)
不过这种方式只适用于修改引用类型字段的场景,若后续需要修改Vertex的其他值类型字段,这种方法就会失效,所以还是方案一更通用。
内容的提问来源于stack exchange,提问作者user1998692
相关产品推荐
相关产品推荐

