Golang 值类型 指针类型
package main import "fmt" type Pomodoro struct { todos []string } type Alice struct { pomodoro map[uint16]Pomodoro } type Alex struct { pomodoro map[uint16]*Pomodoro } func main() { // 指针map演示 alex := Alex{pomodoro: make(map[uint16]*Pomodoro)} alex.pomodoro[1] = &Pomodoro{todos: []string{"初始任务"}} // 修改指针指向的内容 alex.pomodoro[1].todos = append(alex.pomodoro[1].todos, "新增任务") fmt.Println(alex.pomodoro[1].todos) // [初始任务 新增任务] // 值map演示 alice := Alice{pomodoro: make(map[uint16]Pomodoro)} alice.pomodoro[1] = Pomodoro{todos: []string{"初始任务"}} // 直接修改副本无效 tmp := alice.pomodoro[1] // alice.pomodoro[1].todos = append(alice.pomodoro[1].todos, "无效新增") // error=> cannot assign to struct field alice.pomodoro[1].todos in mapcompilerUnaddressableFieldAssign tmp.todos = append(tmp.todos, "无效新增") fmt.Println(alice.pomodoro[1].todos) // [初始任务] (未改变) // 正确修改方式 tmp = alice.pomodoro[1] tmp.todos = append(tmp.todos, "有效新增") alice.pomodoro[1] = tmp fmt.Println(alice.pomodoro[1].todos) // [初始任务 有效新增] }
你的代码很好地展示了在Go语言中使用指针和值类型作为map
的值时的区别。通过对比Alex
和Alice
两个结构体,我们可以清楚地看到直接操作值类型映射与操作指向值类型的指针映射的不同之处。
代码分析
-
对于
Alex
结构体:- 使用了指针类型的
map
,即map[uint16]*Pomodoro
。 - 这意味着你可以直接修改
Pomodoro
实例的内容,因为你是通过指针访问它们的。因此,在你向todos
列表添加新任务时,原始数据被修改了。
- 使用了指针类型的
-
对于
Alice
结构体:- 使用的是值类型的
map
,即map[uint16]Pomodoro
。 - 当你尝试直接修改从映射中获取的
Pomodoro
实例的字段时(如注释所示),这是不允许的,因为你不能直接修改从映射中检索出来的结构体副本。 - 正确的做法是先将副本修改完毕后再将其赋值回映射中,以更新原始数据。
- 使用的是值类型的
关键点总结
-
使用指针:当你希望对映射中的元素进行修改而不必每次都重新赋值回映射时,使用指针是一个好选择。这使得可以直接修改对象,避免不必要的复制开销。
-
使用值类型:如果你不打算修改映射中的元素,或者元素非常小,使用值类型可能是更简单的方式。但是,如果需要修改,则需要先修改副本再将整个副本赋值回映射中。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验