指针类型
在正式介绍 unsafe 包之前,需要着重介绍 Go 语言中的指针类型。
我本科开始学编程的时候,第一门语言就是 C。之后又陆续学过 C++,Java,Python,这些语言都挺强大的,但是没了 C 语言那么“单纯”。直到我开始接触 Go 语言,又找到了那种感觉。Go 语言的作者之一 Ken Thompson 也是 C 语言的作者。所以,Go 可以看作 C 系语言,它的很多特性都和 C 类似,指针就是其中之一。
然而,Go 语言的指针相比 C 的指针有很多限制。这当然是为了安全考虑,要知道像 Java/Python 这些现代语言,生怕程序员出错,哪有什么指针(这里指的是显式的指针)?更别说像 C/C++ 还需要程序员自己清理“垃圾”。所以对于 Go 来说,有指针已经很不错了,仅管它有很多限制。
package main
import "fmt"
func add(x int) {
x+=x
}
func main() {
var a=5
add(a)
fmt.Println(a) // 5
}
非常简单,我想在add()函数里将变量a翻倍,但是例子中的函数却做不到。为什么?因为Go语言中的函数传参都是值传递。add()函数里的形参x只是实参a的一份值拷贝,在函数内部对x的操作不能反馈到实参a上。
然而,相比于 C 语言中指针的灵活,Go 的指针多了一些限制。但这也算是 Go 的成功之处:既可以享受指针带来的便利,又避免了指针的危险性。
限制一:Go语言指针不能运算
a:=5
p:=&a
p++ //invalid operation: p++ (non-numeric type *int)
p=&a+3 //invalid operation: &a + 3 (mismatched types *int and int)
unsafe 实现原理
我们来看源码:
type ArbitraryType int
type Pointer *ArbitraryType
从命名来看,Arbitrary
是任意的意思,也就是说 Pointer 可以指向任意类型,实际上它类似于 C 语言里的 void*
。