1. 写在最前面
最近 review 代码的时候,遇到了很多 map[string]pointer
的写法,之前这种写法的时候,笔者总是以 C/C++ 的角度思考,这样写其实是为了节省内存,但其实不然,除了节省内存,还有其他的意义。
2. 值 vs 指针修改生效问题
先看一个例子,定义一个结构体,其存在两种方法:
- 值类的方法
- 指针类的方法
package main
import "fmt"
type Person struct {
name string
age int
}
// 指针类的方法
func (p *Person) updateName(n string) {
p.name = n
}
// 值类的方法
func (p Person) updateAge(a int) {
p.age = a
}
func updateByValue() {
p := Person{
name: "xiyan",
age: 28,
}
fmt.Printf("updateByValue before %v\n", p)
p.updateAge(29)
p.updateName("new-xiyan")
fmt.Printf("updateByValue after %v\n", p)
}
func updateByPointer() {
p := &Person{
name: "xiyan",
age: 28,
}
fmt.Printf("updateByPointer before %v\n", p)
p.updateAge(29)
p.updateName("new-xiyan")
fmt.Printf("updateByPointer after %v\n", p)
}
func main() {
updateByValue() // 值的修改方法不生效
fmt.Println("=================================")
updateByPointer() // 指针的修改方法生效
}
结论:只有定义为指针的方法的修改才能生效。
3. 值 vs 指针修改寻址问题
还是上述的例子,直接寻址 map 中定义的值和指针类型的结构体:
package main
type Person struct {
name string
age int
}
func (p *Person) updateName(n string) {
p.name = n
}
func (p Person) updateAge(a int) {
p.age = a
}
func main() {
m1 := map[string]*Person{
"xiyan": {
name: "xiyan",
age: 28,
},
}
// 指针类型的结构体能够直接寻址
(m1["xiyan"]).name = "hehe"
m2 := map[string]Person{
"xiyan": {
name: "xiyan",
age: 28,
},
}
// 值类型的结构体不能够直接寻址
(m2["xiyan"]).name = "hehe"
(m2["xiyan"]).age = 29
}
结论:值类型结构体上的寻址会报错。cannot assign to struct field xxx in map
4. Why 什么值类型无法寻址
m2 的 value 存储的是 Person 结构体的值,所有m2[“xiyan”] 不是一个常规的可寻址值:hashmaps 可以在运行时增长,然后它们的值在内存中移动,旧位置变得过时。那么映射实现的内部结构就会暴露出来。
m1 的 value 存储的是 Person 结构体的指针,其结构体占用的内存已经分配成功,且不会随着 hashmaps 的扩容而改变,所以 m1[“xiyan”] 是可寻址的值。
5. 碎碎念
哎,今天真的是各种撕,快疯了的一天:
- 女孩子太容易自责和自我否定。这个世界有时候是有点问题的,你要学会明辨是非。而不是人云亦云。大家都说女孩子要听话,要主内,问问你自己的内心,你真的愿意这样做吗?如果不愿意,就学会说 NO,爱自己就是做自己喜欢的事情,只要不违反法律和道德,与世界为敌又如何?
- ♡ 盐于律己,甜以待人