您诸位好啊,我是无尘,又到周末了,放松之余别忘了“卷”篇文章哟~
在 Go 语言中,处于安全考虑,是不允许两个指针类型进行转换的,比如 *int 不能转为 *float64。
func main() {
i := 5
ip := &i
var fp *float64 = (*float64)(ip)
}
运行结果:
cannot convert ip (type * int) to type * float64
发现报错了,并不能进行强制转型。
如果你非要~,那么 Go 提供了 unsafe
包,使用包里的 Pointer
来进行转换!
unsafe.Pointer 是一种特殊意义的指针,可以表示任意类型的地址。使用它可以进行两个指针类型的转换。
func main() {
i:= 5
ip := &i
var fp *float64 = (*float64)(unsafe.Pointer(ip))
*fp = *fp * 6
fmt.Println(i)
}
示例中我们通过 unsafe.Pointer 可以在不同指针类型之间做任何转换。我们看下 unsafe.Pointer 的源码定义:
// ArbitraryType is here for the purposes of documentation
// only and is not actually part of the unsafe package.
// It represents the type of an arbitrary Go expression.
type ArbitraryType int
type Pointer *ArbitraryType
❝
❞
uintptr 也是一种指针类型,也可以表示任何类型,和 unsafe.Pointer 的区别是,「uintptr 可以进行运算」。通过 uintptr 可以对指针偏移进行计算,来达到访问特定的内存,对特定内存进行读写的目的。 示例:
func main() {
p := new(person)
//Name是person的第一个字段不用偏移,即可通过指针修改
pName := (*string)(unsafe.Pointer(p))
*pName = "微客鸟窝"
//Age并不是person的第一个字段,所以需要进行偏移,这样才能正确定位到Age字段这块内存,才可以正确的修改
pAge := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(p))+unsafe.Offsetof(p.Age)))
*pAge = 20
fmt.Println(*p)
}
type person struct {
Name string
Age int
}
//运行结果:
{微客鸟窝 20}
解析:
❝
p :=new(person)
p.Name = "微客鸟窝"
p.Age = 20
fmt.Println(*p)
}
❞
三种指针类型:*T、unsafe.Pointer、unitptr
*T ←互转→ unsafe.Pointer ←互转→ unitptr
Sizeof 函数可以返回一个类型所占用的内存大小,这个大小只与类型有关,和类型对应的变量存储的数据大小无关,比如 bool 型占用一个字节、int8 也占用一个字节。 通过 Sizeof 函数可以查看任何类型占用的内存大小,示例:
package main
import (
"fmt"
"unsafe"
)
func main() {
fmt.Println(unsafe.Sizeof(true)) //1
fmt.Println(unsafe.Sizeof(int8(0 //1
fmt.Println(unsafe.Sizeof(int16(10))) //2
fmt.Println(unsafe.Sizeof(int32(10000000))) //2
fmt.Println(unsafe.Sizeof(int64(10000000000000))) //1
fmt.Println(unsafe.Sizeof(int(10000000000000000)))
fmt.Println(unsafe.Sizeof(string("微客鸟窝")))
fmt.Println(unsafe.Sizeof([]string{"有码无尘","无尘"}))
}