GolangError指南(一) cannot assign to struct field list[“fruit”].Name in map
GolangError 防踩坑,无法分配给 map 中的结构体字段 name文章目录
一、Golang Error?
Go 语言自发布以来,一直以高性能、高并发著称。不过,任何事情都有两面性。一门语言,有它值得骄傲的优点,也必定都会存在编译报错的情况。
- panic 这个词,在英语中具有恐慌、恐慌的等意思。在 Go 语言中,也代表极其严重的问题,意味着程序的结束并退出。
Go 语言中 panic 关键字主要用于主动抛出异常。
- recover 这个词,在英语中具有恢复、复原等意思。在 Go 语言中,代表将程序状态从错误中恢复到正常状态。
Go语言中 recover 关键字主要用于捕获异常,让程序回到正常状态。
二、错误原因
初始结构体
type Fruit struct { Name string }
1.错误代码
map[string]Fruit 的value是一个Fruit,而list[“fruit”] 是值引用,是只读的。所以对list[“fruit”].Name = "banana"的修改是不允许的。:
// error
list = make(map[string]Fruit)
fruit := Fruit{
"apple"}
list["fruit"] = fruit
//map[string]Fruit 的value是一个Fruit
//而list["fruit"] 是值引用,是只读的。
//所以对list["fruit"].Name = "banana"的修改是不允许的。
list["fruit"].Name = "banana"
fmt.Println(list["fruit"])
2.较差代码
由于值引用是只读的,我们需要绕过引用才可以进行修改,可以先做一次值拷贝,做出一个 tmp ,然后修改 tmp.Name = “banana” ,此时 tmp 内已经修改,那么直接将 map[string]Fruit 的value 的值替换为 tmp ,此时再发生一次值拷贝,list[“fruit”] = tmp,尽管达成目的,但是这种会在整体过程中发生2次结构体值拷贝,性能很差。:
// bad
list := make(map[string]Fruit)
fruit := Fruit{
"apple"}
list["fruit"] = fruit
//由于值引用是只读的,我们需要绕过引用才可以进行修改
//先做一次值拷贝,做出一个 tmp ,然后修改 tmp.Name = "banana" ,
//此时 tmp 内已经修改,那么直接将 map[string]Fruit 的value 的值替换为 tmp
//此时再发生一次值拷贝,list["fruit"] = tmp,
//尽管达成目的,但是这种会在整体过程中发生2次结构体值拷贝,性能很差。
tmp := list["fruit"]
tmp.Name = "banana"
list["fruit"] = tmp
fmt.Println(list["fruit"])
3.好的代码
我们将 map[string]Fruit 变成引用指针的 map[string]*Fruit,这样,我们实际上每次修改的都是指针所指向的Fruit空间,尽管指针本身是常指针,不能修改,是只读属性,但是我们的每次修改并不是修改指针,而是修改指针指向的Fruit,而这是可以随便修改的,修改也不需要值拷贝。:
// perfect
list := make(map[string]*Fruit)
fruit := Fruit{
"apple"}
list["fruit"] = &fruit
// 我们将 map[string]Fruit 变成引用指针的 map[string]*Fruit
// 这样,我们实际上每次修改的都是指针所指向的Fruit空间,
// 尽管指针本身是常指针,不能修改,是只读属性,
// 但是我们的每次修改并不是修改指针,
// 而是修改指针指向的Fruit,而这是可以随便修改的,修改也不需要值拷贝。
list["fruit"].Name = "banana"
fmt.Println(list["fruit"])
总结
Golang 通过指针操作来简便我们的使用习惯与内存占用情况,当我们发现无法修改值或者需要多次修改同一个字段时,不妨想想指针能不能达到我们的要求。
希望这个博客能对你有所益处。我是轻王,我为自己代言。