go语言基本类型
类型名称 | 有无符号 | 占用位数 |
int8 | Yes | 8 |
int16 | Yes | 16 |
int32 | Yes | 32 |
int64 | yes | 64 |
uint8 | No | 8 |
uint16 | No | 16 |
uint32 | No | 32 |
uint64 | No | 64 |
int | Yes | 32或64,等于cpu位数 |
uint | No | 32或64,等于cpu位数 |
rune | No | 32,与uint32等价 |
byte | No | 8,与uint8等价 |
uintptr | No | 64,与uint64等价 |
rune 类型是 Unicode 字符类型,和 uint32 类型等价,通常用于表示一个 Unicode 字符。rune 和 uint32 可以互换使用。
byte 类型与uint8类型等价,byte类型一般用于强调数值是一个原始的内存数据而不是 一个小的整数。
uintptr 是一种无符号的整数类型,与uint64等价,范围:0 ~ 18446744073709551615,足以容纳任何指针值转换来的整型值。 uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。
不管它们的具体大小,int、uint和uintptr是不同类型的兄弟类型。其中int和int32也是 不同的类型, 即使int的大小也是32bit,在需要将int当作int32类型的地方需要一个显式的类型转换操作,反之亦然
unsafe.Pointer
一个可以指向任意类型的指针,不可以进行数值计算
有四种区别于其他类型的特殊操作:
1. 任意类型的指针值均可转换为 Pointer
2. Pointer 均可转换为任意类型的指针值
3. uintptr 均可转换为 Pointer
4. Pointer 均可转换为 uintptr
示例1(unsafe.Pointer用来取地址,uintptr用来取地址的10进制数值):
package main
import (
"fmt"
"unsafe"
)
func main() {
a := int(5)
p := &a
fmt.Println("p:", p) // a的地址,16进制形式
fmt.Println("unsafe.Pointer(&a):", unsafe.Pointer(&a)) // a的地址,16进制形式
fmt.Println("uintptr(unsafe.Pointer(&a)):", uintptr(unsafe.Pointer(&a))) // a的地址,10进制形式
}
结果如下图:
PS:每次运行a的地址可能是不同的,但 unsafe.Pointer(&a) 和 uintptr(unsafe.Pointer(&a))的值是一样的,只是前者是指针类型,16进制,后者是整数类型,10进制,两者相等,这里 0xc00000a0b8,转换为10进制即 824633761976
示例2(地址计算,偏移,并修改)
package main
import (
"fmt"
"unsafe"
)
func main() {
a := [4]int{0, 1, 2, 3}
p1 := unsafe.Pointer(&a[1]) // p1指向a[1]的起始地址
// a[1]的地址类型转换为uintptr类型,后移2个元素的位置,这样移动到a[3]的起始地址位置
p3 := unsafe.Pointer(uintptr(p1) + 2 * unsafe.Sizeof(a[0]))
*(*int)(p3) = 6 // 先将Pointer类型转换为*int类型,再赋值
fmt.Println("a =", a) // 打印出来结果是:a = [0 1 2 6]
}
结果如下图:
PS:unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为 uintptr 进行指针运算
示例3(unsafe.Offsetof的使用)
该函数返回属性x的起始地址和结构体起始地址的字节数
func Offsetof(x ArbitraryType) uintptr
代码如下:
package main
import (
"fmt"
"unsafe"
)
type Person struct {
name string
age int
gender bool
}
func main() {
john := Person{"John", 30, true}
pp := unsafe.Pointer(&john) // 结构体的起始地址
pname := (*string)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.name))) // 属性name的起始地址,转换为*string类型
page := (*int)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.age))) // 属性age的起始地址,转换为*int类型
pgender := (*bool)(unsafe.Pointer(uintptr(pp) + unsafe.Offsetof(john.gender))) // 属性gender的起始地址,转换为*bool类型
// 进行赋值
*pname = "Alice"
*page = 28
*pgender = false
fmt.Println(john) // {Alice 28 false}
}
实验结果如下: