我们如何知道字节数组中的结构类型呢?

huangapple go评论93阅读模式
英文:

How we can know what kind of struct is on byte array

问题

我正在寻找一种方法来确定哈希的结构类型。有没有可能在不尝试错误方法(将其转换为特定类型并查看转换是否成功)的情况下实现这一点?

请检查以下代码:

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"reflect"
)

type T struct {
	A int64
	B float64
}

type D struct {
	A int64
	B float64
	C string
}


func main() {
	// 创建一个结构体并将其写入缓冲区。
	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 "是类型 T"
    	case D:
        	return "是类型 D"
    	default:
        	_ = t
        	return "未知类型";
    }
}

希望这可以帮助你。

英文:

I'm looking for some solution to know whats the struct type of the hash. It is possible to do that without try an error method (casting to a specific type and see the cast is successfully)?

Please check the code:

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"
    }
}

答案1

得分: 1

由于encoding/binary包不会写出类型信息,因此无法确定写入/序列化的类型。

而且你的处境比你最初想的还要糟糕:即使尝试将其解码为不同类型的值,也可能成功而没有错误,因此甚至没有可靠的方法来确定类型。

例如,如果你序列化了这种类型的值:

type T struct {
	A int64
	B float64
}

你可以将其读入这种类型的值:

type T2 struct {
	B float64
	A int64
}

它不会报错,因为两个结构体的大小相同,但显然字段中的数字是不同的。

如果你使用encoding/gob,你的处境会稍微好一些,因为gob包会传输类型信息,将类型为T的值编码然后解码为类型为T2的值是可行的:字段的顺序不重要,额外或缺少的字段也不会引起问题。

看看这个例子:

// 创建一个结构体并写入它。
t := T{A: 0xEEFFEEFF, B: 3.14}
fmt.Println("编码:", 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上尝试):

编码: {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}

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

英文:

Since the encoding/binary package does not write out type information, it is not possible to tell what type was written / serialized.

And you're in a worse position that you might originally think: even trying to decode into a value of different type might succeed without errors, so there isn't even a reliable way to tell the type.

For example if you serialize a value of this type:

type T struct {
	A int64
	B float64
}

You can read it into a value of this type:

type T2 struct {
	B float64
	A int64
}

It will give no errors because the size of both structs is the same, but obviously you will get different numbers in the fields.

You are in a little better position if you use encoding/gob, as the gob package does transmit type information, and encoding a value of type T and then decoding it into a value of type T2 would work: order of fields does not matter, and extra or missing fields also do not cause trouble.

See this example:

// Create a struct and write it.
t := T{A: 0xEEFFEEFF, B: 3.14}
fmt.Println(&quot;Encoding:&quot;, t)
buf := &amp;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, &amp;t2))
fmt.Println(t2)

t2 = T2{}
fmt.Println(gob.NewDecoder(buf).Decode(&amp;t2))
fmt.Println(t2)

Output (try it on the Go Playground):

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

If you want to be able to detect the type before reading it, you have to take care of it yourself: you have to transmit type information (e.g. name of the type). Or even better, use a serialization method that already does this, for example Google's protocol buffers, and here is the Go implementation for it: github.com/golang/protobuf.

huangapple
  • 本文由 发表于 2017年1月11日 18:59:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/41589055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定