Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go语言指针的用法和使用限制 #41

Open
kevinyan815 opened this issue Jan 2, 2021 · 0 comments
Open

Go语言指针的用法和使用限制 #41

kevinyan815 opened this issue Jan 2, 2021 · 0 comments

Comments

@kevinyan815
Copy link
Owner

基础知识

指针保存着一个值的内存地址,类型 *T代表指向T 类型值的指针。其零值为nil

&操作符为它的操作数生成一个指针。

i := 42
p = &i

*操作符则会取出指针指向地址的值,这个操作也叫做“解引用”。

fmt.Println(*p) // 通过指针p读取存储的值
*p = 21         // 通过指针p设置p执行的内存地址存储的值

为什么需要指针类型呢?参考这样一个例子:

package main

import "fmt"

func double(x int) { 
   x += x
}

func main() { 
   var a = 3 
   double(a)
    fmt.Println(a) // 3
}

在 double 函数里将 a 翻倍,但是例子中的函数却做不到。为什么?因为 Go 语言的函数传参都是 值传递。double 函数里的 x 只是实参 a 的一个拷贝,在函数内部对 x 的操作不能反馈到实参 a。

如果这时,有一个指针就可以解决问题了。

package main
import "fmt"

func double(x *int) { 
   *x += *x
    x = nil
}

func main() {
    var a = 3
    double(&a)
    fmt.Println(a) // 6
    p := &a
    double(p)
    fmt.Println(a, p == nil) // 12 false
}

很常规的操作,不用多解释。唯一可能有些疑惑的在这一句:

x = nil

这得稍微思考一下,才能得出这一行代码根本不影响的结论。因为参数都是值传递,所以 x 也只是对 &a 的一个拷贝。

*x += *x

这一句把 x 指向的值(也就是 &a 指向的值,即变量 a)变为原来的 2 倍。但是对 x 本身(一个指针)的操作却不会影响外层的 a,所以在double函数内部的 x=nil 不会影响外面。

函数内部指针指向变换的过程

Go语言指针的限制

出于安全方面的考虑,相较于 C 语言指针的灵活,Go语言里指针多了不少限制,不过这也算是 Go 的成功之处:既可以享受指针带来的便利,又避免了指针的危险性。

限制一:指针不能参与运算

来看一个简单的例子:

package main

import "fmt"

func main() {
	a := 5
	p := a
	fmt.Println(p)
	p = &a + 3
}

上面的代码将不能通过编译,会报编译错误:

invalid operation: &a + 3 (mismatched types *int and int)

也就是说 Go 不允许对指针进行数学运算。

限制二:不同类型的指针不允许相互转换。

下面的程序同样也不能编译成功:

package main

func main() {
	var a int = 100
	var f *float64
	f = *float64(&a)
}

限制三:不同类型的指针不能比较,也不能相互赋值

这条限制同上面的限制二,因为指针之间不能做类型转换,所以也没法使用==或者!=进行比较了,同学不同类型的指针变量相互之间不能赋值。比如下面这样,也是会报编译错误。

package main

func main() {
	var a int = 100
	var f *float64
	f = &a
}

Go语言的指针是类型安全的,但它有很多限制,所以 Go 还有非类型安全的指针,这就是 unsafe 包提供的 unsafe.Pointer。在某些情况下,它会使代码更高效,当然,也更危险。 具体用法放到后面 unsafe.Pointer 的模块里细说。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant