TreeviewCopyright © aleen42 all right reserved, powered by aleen42

unsafe

uintptr是整型,可以足够保存指针的值得范围,在32平台下为4字节,在64位平台下是8字节

unsafe他是一个可以像c语言那样操作指针的东西 先看一个例子。

package main

import (
    "fmt"
)

func main() {
    var n int32 =2
    var m int64 =3

    n = int32(m)
    fmt.Println(n)
}

普通的类型转化,由于降低了精度所以需要注意,但编译器不会有任何报错,程序可以执行,譬如下面

package main

import (
    "fmt"
)

func main() {
    var n int32 =2
    var m int64 =0xFFFFFFFFFFFFFF

    n = int32(m)
    fmt.Println(n)
}

只是执行结果是:-1 但程序不会有任何问题。 但如果是指针的强转则会出现问题。

*int32(&n)

这样的操作是不允许的,因为指针的操作已经越界了,golang不允许这样访问,那如果你还是想这样玩怎么办 就是上面说的unsafe包,来完成。

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var n int32 =2
    var m int64 =3

    p := (*int64)(unsafe.Pointer(&n))
    *p = m
    fmt.Println(n)
}

输出的结果是:3 这样就可以完成数据的操作了。

看下面这个数组,这个例子更有趣

func main() {

    var m [2]int8

    p := (*int)(unsafe.Pointer(&m[0]))
    *p = 0x1010
    fmt.Println(m)

}

输出的结果是:[16 16] 如果m是int16的数组,结果是:[4112 0] 这样就完成了数组的赋值。

还可以深入做一个切片函数:


type SliceHeader struct {
    Data unsafe.Pointer
    Len  int64
    Cap  int64
}

type StringHeader struct {
    Data unsafe.Pointer
    Len  int64
}

func slice(s []int, b, l int64)([]int){
    p := (*SliceHeader)(unsafe.Pointer(&s))
    p.Len = l
    p.Cap = int64(cap(s))
    p.Data = unsafe.Pointer(&s[b])
    return *(*[]int)(unsafe.Pointer(p))
}

func slicestr(s string,b ,l int) (string){
    p := (*StringHeader)(unsafe.Pointer(&s))
    p.Data = unsafe.Pointer(uintptr(p.Data) + uintptr(b))
    p.Len = int64(l)
    return *(*string)(unsafe.Pointer(p))
}


func main() {

    var m [5]int
    s :=m[1: 3]

    fmt.Println(len(s))
    fmt.Println(cap(s))
    fmt.Println(s)
    s = slice(s,0,1)
    fmt.Println(len(s))
    fmt.Println(cap(s))
    fmt.Println(s)

    str := "hello"
    newstr := slicestr(str,1,7)
    fmt.Println(newstr)

}

输出的结果是:

2
4
[0 0]
1
4
[0]
elloint1

上面最后一张的输出需要注意,建议将len设置成字符串的长度,否则会读取到不应该读取的内容。

最后还可以实现字符串的0拷贝,这个是比较有意思的

func main() {

     m := []byte{'h','e','l','l','o'}
     fmt.Println(string(m))
     p := SliceHeader{
         Data: unsafe.Pointer(&m[0]),
         Len: int64(len(m)),
     }

     str := *(*string)(unsafe.Pointer(&p))
    fmt.Println(str)

}

当然不建议这么使用,比较危险,因为gc回收m。可能导致出错

results matching ""

    No results matching ""