第一式 - 获得Slice和String的内存数据
func stringPointer(s string) unsafe.Pointer { p := (*reflect.StringHeader)(unsafe.Pointer(&s)) return unsafe.Pointer(p.Data) } func bytePointer(b []byte) unsafe.Pointer { p := (*reflect.SliceHeader)(unsafe.Pointer(&b)) return unsafe.Pointer(p.Data) }
第二式 - 把[]byte转成string
package test import "testing" import "unsafe" func Test_ByteString(t *testing.T) { var x = []byte("Hello World!") var y = *(*string)(unsafe.Pointer(&x)) var z = string(x) if y != z { t.Fail() } } func Benchmark_Normal(b *testing.B) { var x = []byte("Hello World!") for i := 0; i < b.N; i ++ { _ = string(x) } } func Benchmark_ByteString(b *testing.B) { var x = []byte("Hello World!") for i := 0; i < b.N; i ++ { _ = *(*string)(unsafe.Pointer(&x)) } }这个实验先证明了我们能够用[]byte的数据造个string给Go。接着做了两组Benchmark,分别測试了普通的类型转换和伪造string的效率。
PASS Benchmark_Normal 20000000 63.4 ns/op Benchmark_ByteString 2000000000 0.55 ns/op ok github.com/idada/go-labs/labs28 2.486s
第三式 - 结构体和[]byte互转
type MyStruct struct { A int B int } var sizeOfMyStruct = int(unsafe.Sizeof(MyStruct{})) func MyStructToBytes(s *MyStruct) []byte { var x reflect.SliceHeader x.Len = sizeOfMyStruct x.Cap = sizeOfMyStruct x.Data = uintptr(unsafe.Pointer(s)) return *(*[]byte)(unsafe.Pointer(&x)) } func BytesToMyStruct(b []byte) *MyStruct { return (*MyStruct)(unsafe.Pointer( (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data, )) }