Golang pointer指针
读书笔记https://go101.org/article/pointer.html
尽管golang吸收了很多其它语言的特点,但是go还是算是C家庭的语言。指针就是其中的一个证据。Go的指针与C指针有相同的地方也有不同的地方。
什么是指针
Go中有一个叫Pointer的类型。
Go Pointer类型与值
类型T的指针可以表示为*T。
关于什么是non-defined pointer和defined pointer
*int // A non-defined pointer type whose base type is int.
**int // A non-defined pointer type whose base type is *int.
// Ptr is a defined pointer type whose base type is int.
type Ptr *int
// PP is a defined pointer type whose base type is Ptr.
type PP *Ptr
显然non-defined pointer具有更好的可读性。
关于引用
指针的值引用了其它值。
有两种方式取到non-nil指针:
- 关键字new,用得比较少。
- 取地址&。
pointer Dereference
也就是取指针的值 *p
如果p为nil,运行时会panic
package main
import "fmt"
func main() {
p0 := new(int) // p0 points to a zero int value.
fmt.Println(p0) // (a hex address string)
fmt.Println(*p0) // 0
// x is a copy of the value at
// the address stored in p0.
x := *p0
// Both take the address of x.
// x, *p1 and *p2 represent the same value.
p1, p2 := &x, &x
fmt.Println(p1 == p2) // true
fmt.Println(p0 == p1) // false
p3 := &*p0 // <=> p3 := &(*p0) <=> p3 := p0
// Now, p3 and p0 store the same address.
fmt.Println(p0 == p3) // true
*p0, *p1 = 123, 789
fmt.Println(*p2, x, *p3) // 789 789 123
fmt.Printf("%T, %T \n", *p0, x) // int, int
fmt.Printf("%T, %T \n", p0, p1) // *int, *int
}
为什么需要指针
go中所有值的赋值都是值拷贝,包括函数参数传递。
package main
import "fmt"
func double(x *int) {
*x += *x
x = nil // the line is just for explanation purpose
}
func main() {
var a = 3
double(&a)
fmt.Println(a) // 6
p := &a
double(p)
fmt.Println(a, p == nil) // 12 false
}
可以返回局部变量的指针,并且是安全的
//这样是允许的
func newInt() *int {
a := 3
return &a
}
指针的限制
Go指针值不支持算术运算
p++, p-2是非法的,主要为了安全。
*p++其实是(*p)++,不算指针的运算
指针值不能转换为任意指针类型
两个类型T1、T2的指针值能转换的前提是:
- T1和T2的底层类型是相同的(忽略struct tags),特别是如果T1,T2是non-define类型并且底层类型是相同的(考虑struct tags),然后转换是隐式的。
- 如果T1和T2都是non-defined类型,并且底层类型是相同的(忽略struct tags)。
type MyInt int64
type Ta *int64
type Tb *MyInt
-
*int64 可以隐含地转换为Ta,反之也行。
-
*MyInt 可以隐含地转换为Tb,反之也行。
-
*MyInt 可以显性地转换为 *int64,反之也行。
-
Ta不能直接转换成Tb,显式也不行。需要
Tb((*MyInt)((*int64)(pa)))
指针值不能和任意指针比较
只有类型相同的指针(或可以进行隐式转换的)才能用==和!=比较,还有nil。
不同类型的指针不能相互赋值
打破上面的限制
使用包unsafe。