为什么golang不能给map中的结构体(struct)直接赋值

今天在写代码的时候遇到了一个错误,

在尝试编译的时候,编译器报了这个错误cannot assign to struct field s.Templates[name].Template in map

探索

这里是出现问题的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type WebTemplate struct {
Name string
Template string
}

type TemplateStore struct {
Templates map[string]WebTemplate
}

func (s *TemplateStore) Modify(name string, content string) {
if _, ok := s.Templates[name]; ok {
s.Templates[name].Template = content // 报错位置在这一行.
return
}
}

在进行了一番搜索之后 https://stackoverflow.com/questions/32751537/why-do-i-get-a-cannot-assign-error-when-setting-value-to-a-struct-as-a-value-i

看了一下,出现这个问题的原因是因为golang对map的实现所造成的。

因为golang的map实际上是一个可以扩展的结构体,也就是说,一个key对应的内存地址可能会因为map的扩大和缩小而产生改变

举个粒子

1
2
3
fmt.Println(&myMap["asdf"]) // 这个时候可能是 0x0010
... // 一堆代码
fmt.Println(&myMap["asdf"]) // 这个时候可能就变成了是 0x0030

所以,为了防止出现用户尝试赋值的时候,key所对应的内存地址发生变化,而导致赋值到错误的地址上。 就直接不让赋值给map中的struct了

解决方式

我的解决方式还是比较简单的。

直接把结构体map[string]WebTemplate 换成指针就行了 map[string]*WebTemplate

因为这样子的话,取值的时候是取到的一个指向WebTemplate的指针地址,这个指针地址是不会变的,所以可以放心赋值。

如果是结构体的话,他返回的是map里的一个地址,是有可能发生改变的