func Encode(i interface{}) ([]byte, error) {
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
// size := unsafe.Sizeof(i)
size := reflect.TypeOf(i).Size()
fmt.Println(size)
ptr := unsafe.Pointer(&i)
startAddr := uintptr(ptr)
endAddr := startAddr + size
for i := startAddr; i < endAddr; i++ {
bytePtr := unsafe.Pointer(i)
b := *(*byte)(bytePtr)
buffer.WriteByte(b)
}
return buffer.Bytes(), nil
}
func TestEncode(t *testing.T) {
test := Test{10, "hello world"}
b, _ := Encode(test)
ptr := unsafe.Pointer(&b)
newTest := *(*Test)(ptr)
fmt.Println(newTest.X)
}
我正在学习如何使用golang unsafe并编写此函数来编码任何对象。我遇到两个问题,第一,剂量unsafe.Sizeof(obj)总是返回obj的指针大小?为什么它与reflect.TypeOf(obj).Size()不同?其次,我想迭代obj的底层字节并通过unsafe.Pointer()将它转换回TestEncode函数中的obj,但是对象的值全部损坏,为什么?
答案 0 :(得分:1)
首先,timestamps = false;
返回需要存储类型的字节。这有点棘手,但它并不意味着需要存储数据的字节。
例如,众所周知,切片在32位机器上存储3个4字节的整数。一个uintptr用于底层数组的内存地址,两个unsafe.Sizeof
用于int32
和len
。因此,无论切片有多长或它是什么类型,切片在32位机器上总是占用12个字节。可能,字符串使用8个字节:1 cap
表示地址,1 uintptr
表示int32
。
至于len
之间的区别,它是关于界面的。 reflect.TypeOf().Size
查看接口并获取具体类型,并报告有关具体类型的所需字节,而reflect.TypeOf
只返回接口类型的8:2 unsafe.Sizeof
指向数据的指针和指向方法列表的指针。
第二部分现在很清楚了。例如,uintptr
采用接口的地址,而不是具体类型。两个,在unsafe.Pointer
中,TestEncode
正在将地址写入12字节切片“标头”。可能还有其他错误,但提到的两个错误,它们没有任何意义。
注意:我避免谈论unsafe.Pointer
和uintptr
的订单,不仅因为我不知道,而且因为他们没有记录,不安全,并且依赖于实施。
注2:结论:不要试图转储Go数据的内存。
注3:我将所有内容更改为32位,因为游乐场正在使用它,因此更容易检查。