10 10
golang里slice与[]byte的零拷贝转换

slice在Go的运行时库中就是一个C语言动态数组的实现,在$GOROOT/src/pkg/runtime/runtime.h中可以看到它的定义:

struct Slice
{   
    byte*    array;        // actual data
    uintgo    len;        // number of elements
    uintgo    cap;        // allocated number of elements
};

所以要实现一个“zero-copy”的转换,我们需要借助unsafe.Pointer的帮助

func stringToBytes(s string) []byte {
    x := (*[2]uintptr)(unsafe.Pointer(&s))
    h := [3]uintptr{x[0], x[1], x[1]}
    return *(*[]byte)(unsafe.Pointer(&h))
}

func bytesToString(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}

func main() {
    s := strings.Repeat("abc", 3)
    b := stringToBytes(s)
    s2 := bytesToString(b)

    fmt.Println(b, s2)
}

还可以这样:

var ptr unsafe.Pointer
var s1 = struct {
    addr uintptr
    len int
    cap int
}{ptr, length, length}
s := *(*[]byte)(unsafe.Pointer(&s1))

或者使用reflect.SliceHeader的方式来构造slice,比较推荐这种做法:

var o []byte
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&o)))
sliceHeader.Cap = length
sliceHeader.Len = length
sliceHeader.Data = uintptr(ptr)