普通指針和unsafe.Pointer類型的指針都能表明引用一個地址,被GC發現。可是uintptr是不表明引用一個地址的。不能被GC發現,若是沒有其餘引用可能會被回收。數組
做用:在函數傳參時修改原值安全
以下,將 *int 類型指針轉化爲 *float 類型函數
var p1* int var p2 unsafe.Pointer var p3* float64 p2 = unsafe.Pointer(p1) p3 = (*float64)(p2) log.Println(reflect.TypeOf(p3))//*float64
uintptr類型能夠進行指針運算,uintptr是個整數,內存地址編號ui
內存地址能夠看作是一個線性的字節數組。按字節編址,存儲單元(8位一個單元)都有一個編號,this
name :="biningo" namep:=unsafe.Pointer(&name) namept:=uintptr(namep) log.Printf("%x %x\n",&name,namept) //c000054200 c000054200
uintptr運算:指針
arr:=[5]int64{1,2,3,4,5} uptr:=uintptr(unsafe.Pointer(&arr)) log.Printf("%x %x\n",uptr,&arr[0]) uptr +=uintptr(8) log.Printf("%x %x\n",uptr,&arr[1]) arr2:=*(*int64)(unsafe.Pointer(uptr)) log.Println(arr2) //2 arr2=100 log.Println(arr[1]) //2 不變 arr3:=(*int64)(unsafe.Pointer(uptr)) *arr3 = 999 log.Println(arr[1]) //999 改變
下面方法返回的都是uintptr類型,uintptr類型是個整數code
Alignof :查詢字節對齊的大小,大部分是8字節,有些是4字節和1字節,有多種類型混合的話就按最大的字節對齊,對象
好比下面,字節對齊對大的是8字節 ,因此都按8字節來對齊內存
type A struct { n int32 s string p *int b bool up uintptr } a:=A{} log.Println(unsafe.Alignof(a.n)) //4 log.Println(unsafe.Alignof(a.s)) //8 log.Println(unsafe.Alignof(a.p)) // log.Println(unsafe.Alignof(a.b))//1 log.Println(unsafe.Alignof(a.up))//8
type S struct { i1 int32 //對齊大小是 4 i2 int32 // } s:=S{} log.Println(unsafe.Offsetof(s.i1))//0 log.Println(unsafe.Offsetof(s.i2))//4 這裏就不是8開始了,由於都是4字節對齊
log.Println(unsafe.Offsetof(a.n)) //0 log.Println(unsafe.Offsetof(a.s)) //8 log.Println(unsafe.Offsetof(a.p)) //24 [+16 string的大小是16字節] log.Println(unsafe.Offsetof(a.b)) //32 log.Println(unsafe.Offsetof(a.up)) //40
下面展現指針堆結構體的操做,下面的操做會改變原來對象的值string
type T struct { t1 byte t2 int32 t3 int64 t4 string t5 bool } //普通指針,用於傳遞對象地址,不能進行指針運算。 // //unsafe.Pointer:通用指針類型,用於轉換不一樣類型的指針,不能進行指針運算。 // //uintptr:用於指針運算,GC 不把 uintptr 當指針,uintptr 沒法持有對象。uintptr 類型的目標會被回收。 func main() { t := &T{1, 2, 3, "this is a example", true} ptr := unsafe.Pointer(t) t1 := (*byte)(ptr) log.Println(*t1) //1 t2 := (*int32)(unsafe.Pointer(uintptr(ptr) + unsafe.Offsetof(t.t2))) *t2 = 99 log.Println(t.t2) //99 被改變了 t3 := (*int64)(unsafe.Pointer(uintptr(ptr) + unsafe.Offsetof(t.t3))) *t3 = 123 log.Println(t.t3) //123 }
下面看看go內置的數據類型slice
type slice struct { array unsafe.Pointer //底層數組的指針 長度是8 len int //切片長度 int型size=8 cap int //切片實際長度 }
int main(){ s := make([]int, 9, 20) var Len = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(8))) log.Println(Len, len(s)) // 9 9 長度是9 var Cap = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(16))) //0+8+8 log.Println(Cap, cap(s)) // 20 20 cap是20 }