golang unsafe将对象编码为字节?

时间:2018-02-07 01:24:08

标签: go

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,但是对象的值全部损坏,为什么?

1 个答案:

答案 0 :(得分:1)

首先,timestamps = false; 返回需要存储类型的字节。这有点棘手,但它并不意味着需要存储数据的字节。

例如,众所周知,切片在32位机器上存储3个4字节的整数。一个uintptr用于底层数组的内存地址,两个unsafe.Sizeof用于int32len。因此,无论切片有多长或它是什么类型,切片在32位机器上总是占用12个字节。可能,字符串使用8个字节:1 cap表示地址,1 uintptr表示int32

至于len之间的区别,它是关于界面的。 reflect.TypeOf().Size查看接口并获取具体类型,并报告有关具体类型的所需字节,而reflect.TypeOf只返回接口类型的8:2 unsafe.Sizeof指向数据的指针和指向方法列表的指针。

第二部分现在很清楚了。例如,uintptr采用接口的地址,而不是具体类型。两个,在unsafe.Pointer中,TestEncode正在将地址写入12字节切片“标头”。可能还有其他错误,但提到的两个错误,它们没有任何意义。

注意:我避免谈论unsafe.Pointeruintptr的订单,不仅因为我不知道,而且因为他们没有记录,不安全,并且依赖于实施。

注2:结论:不要试图转储Go数据的内存。

注3:我将所有内容更改为32位,因为游乐场正在使用它,因此更容易检查。