1-7 指针
在go语言中定义指针时,支持指针类型 *T,指针的指针 **T,以及包含包名前缀的 *.T。
指针的特性
- 默认值 nil,没有 NULL 常量。
- 操作符 “&” 取变量地址,"*" 透过指针访问目标对象。
- 不支持指针运算,不支持 “->” 运算符,直接用 “.” 访问目标成员。
package main
import "fmt"
func main() {
type data struct {
a int
}
var d = data{1234}
var p *data
p = &d
fmt.Printf("%p, %v\n", p, p.a) // 直接用指针访问目标对象成员,无须转换。
}
- 使用unsafe.Pointer对指针进行类型转换
func func1() {
x := 0x12345678
p := unsafe.Pointer(&x) // *int -> Pointer
n := (*[4]byte)(p) // Pointer -> *[4]byte
for i := 0; i < len(n); i++ {
fmt.Printf("%X ", n[i])
}
}
Go语言在设计的时候,为了编写方便、效率高以及降低复杂度,被设计成为一门强类型的静态语言。强类型意味着一旦定义了,它的类型就不能改变了;静态意味着类型检查在运行前就做了。
同时为了安全的考虑,Go 语言是不允许两个指针类型进行转换的。
我们一般使用*T作为一个指针类型,表示一个指向类型T变量的指针。为了安全的考虑,两个不同的指针类型不能相互转换,比如*int 不能转为*float64。
而unsafe.Pointer 是一种特殊意义的指针,它可以包含任意类型的地址,有点类似于 C 语言里的void*指针,全能型的。也就意味着它某种程度上可以进行类型转换。
- 将 Pointer 转换成 uintptr,可变相实现指针运算
func main() {
d := struct {
s string
x int
}{"abc", 100}
p := uintptr(unsafe.Pointer(&d)) // *struct -> Pointer -> uintptr
p += unsafe.Offsetof(d.x) // uintptr + offset
p2 := unsafe.Pointer(p) // uintptr -> Pointer
px := (*int)(p2) // Pointer -> *int
*px = 200 // d.x = 200
fmt.Printf("%#v\n", d)
}