如何知道字节数组中的结构类型



我正在寻找一些解决方案来了解哈希的结构类型。是否可以在不尝试错误方法的情况下做到这一点(转换为特定类型并查看转换是否成功)?

请检查代码:

import (
"bytes"
"encoding/binary"
"fmt"
"reflect"
)
type T struct {
A int64
B float64
}
type D struct {
A int64
B float64
C string
}

func main() {
// Create a struct and write it.
t := T{A: 0xEEFFEEFF, B: 3.14}
buf := &bytes.Buffer{}
err := binary.Write(buf, binary.BigEndian, t)
if err != nil {
panic(err)
}
fmt.Println(buf.Bytes())
out := getType(buf)
fmt.Println(out)
}
func getType(v interface{})(r string){
fmt.Println(reflect.TypeOf(v))
switch t := v.(type) {
case T:
return "Is type T"
case D:
return "Is type D"
default:
_ = t
return "unknown"
}
}

由于encoding/binary包不写类型信息,因此无法判断写入/序列化了什么类型。

而且你的处境比你最初想象的更糟:即使试图解码成不同类型的值也可能成功而没有错误,所以甚至没有可靠的方法来判断类型。

例如,如果您序列化以下类型的值:

type T struct {
A int64
B float64
}

您可以将其读取为以下类型的值:

type T2 struct {
B float64
A int64
}

它不会出错,因为两个结构的大小相同,但很明显,字段中的数字不同。

如果使用encoding/gob,情况会好一点,因为gob包确实传输类型信息,对T类型的值进行编码,然后将其解码为T2类型的值会起作用:字段的顺序无关紧要,额外或丢失的字段也不会造成麻烦。

参见此示例:

// Create a struct and write it.
t := T{A: 0xEEFFEEFF, B: 3.14}
fmt.Println("Encoding:", t)
buf := &bytes.Buffer{}
fmt.Println(binary.Write(buf, binary.BigEndian, t))
fmt.Println(buf.Bytes())
fmt.Println(gob.NewEncoder(buf).Encode(t))
t2 := T2{}
fmt.Println(binary.Read(buf, binary.BigEndian, &t2))
fmt.Println(t2)
t2 = T2{}
fmt.Println(gob.NewDecoder(buf).Decode(&t2))
fmt.Println(t2)

输出(在Go Playground上尝试):

Encoding: {4009750271 3.14}
<nil>
[0 0 0 0 238 255 238 255 64 9 30 184 81 235 133 31]
<nil>
<nil>
{1.9810798573e-314 4614253070214989087}
<nil>
{3.14 4009750271}

如果你想在阅读之前检测到类型,你必须自己处理:你必须传输类型信息(例如类型的名称)。或者更好的是,使用一种已经做到这一点的序列化方法,例如谷歌的协议缓冲区,下面是它的Go实现:github.com/golang/protobuf.

最新更新