go接收者和锁注意事项
go接收者和锁注意事项
-
如果需要修改对象中的值,建议使用指针接收者。如果不需要修改对象中的值,建议使用值接收者。
-
代码
package main import ( "fmt" ) type Student struct { Name string Age int } func (s Student) UpdateName(name string) { s.Name = name } func (s *Student) UpdateAge(age int) { s.Age = age } func main() { s := Student{Name: "jom", Age: 20} fmt.Println(s) s.UpdateName("tim") fmt.Println(s) s.UpdateAge(22) fmt.Println(s) }
-
输出
{jom 20} {jom 20} {jom 22}
-
从输出可以分析出来,当为值接收者的时候,也就是
(s Student)
,是不会修改对象值的。当为指针接收者的时候,也就是(s *Student)
,是会修改对象值的。从代码上看,这是因为无论何时调用UpdateName
函数,s
都会是一份值拷贝,无论怎么修改UpdateName
函数中s
的值,都不会对main
函数中的s
值有任何的影响。而UpdateAge
函数,s
是指针,也就是在调用的时候指针接收者s
的地址和main
函数中s
的地址是一致的,使用指针接收者进行修改,会对main
函数中的s
的值有影响。
-
-
锁的拷贝是建立新的锁
- 代码
package main import ( "fmt" "sync" "time" ) type Class struct { sync.Mutex Student map[string]int } func (c Class) inc(key string) { c.Lock() defer c.Unlock() c.Student[key]++ } func main() { c := Class{Student: map[string]int{"aa": 0, "bb": 0}} do := func(key string, frequency int) { for i := 0; i < frequency; i++ { c.inc(key) } } go do("aa", 1000) go do("aa", 1000) time.Sleep(10 * time.Second) fmt.Println(c.Student) }
- 输出
fatal error: concurrent map writes
- 从结果看来是
map
的读写冲突了。从代码上看,这是因为我们调用c.inc
函数的时候,对main
函数中的c进行了拷贝,而c
中字段Mutex
由于是值类型,在拷贝的时候也拷贝了一份,而c
中的map
由于是引用类型,依然是指向同一个map
。这样就会造成两或两个以上的协程同时修改map
中的值时,对map
的互斥失效,从而导致的写冲突。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)