[Golang] 指针类型和非指针类型的一个比较有意思的案例
程序员文章站
2024-03-12 22:42:27
...
前景提要:
在用golang开发的时候难免会碰到并发的情况,要控制数据的一致性的时候就得用到锁这个对象。我定义的一个结构体里面声明sync.Map或者sync.Mutex。我发现可以直接用这个结构体里面的sync对象去lock。这是一个比较有意思的现象,我们知道如果nil去调用就会引发panic。这可能就涉及到一些指针和非指针初始化的概念。
案例介绍
接下来就简单的演示一下代码和从sync的源码上面分析一波为什么可以直接使用函数而不需要做任何的初始化。
结构体里面就只定义一个互斥锁的值类型对象。
package main
import (
"fmt"
"sync"
)
type foo struct {
l sync.Mutex
}
func main() {
f := foo{}
f.l.Lock()
fmt.Println("hello world")
f.l.Unlock()
}
上面的代码执行结果就是“hello world”。
结构体里面就只定义一个互斥锁的指针类型对象。
package main
import (
"fmt"
"sync"
)
type foo struct {
l *sync.Mutex
}
func main() {
f := foo{}
f.l.Lock()
fmt.Println("hello world")
f.l.Unlock()
}
上面的代码执行结果就是直接panic。上面的这两个结果还是比较有意思的。指针类型和值类型的初始化为啥会引发这么大的差别。
结论是因为sync.Mutex这个结构体里面就是两个基础类型,一个是int32,一个是uint32. 如果值类型自动初始化的话会是0,也就是说这个结构对象直接是{0,0}。但是如果是指针类型的话,就会是nil。nil直接去调用用接受者是他本身的方法就会直接报panic,值类型反而不会报错就是因为0的存在。 mutex的结构如下。sync的map也是用的mutex,所以本质上还是一样的。
type Mutex struct {
state int32
sema uint32
}
总结
这个设计还是很有意思的。这种设计要怎么引入到客户端而不那么突兀也是一个值得思考的问题。这里也引发了另外一个问题,什么时候用指针,什么时候用值类型,config如果用指针的话,怎么在入口打印参数的时候不显示地址直接显示值?
上一篇: 用Java程序判断是否是闰年的简单实例