在Go语言中,如何将数据反序列化为正确的顺序?

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

How do you Unmarshall into the correct order in Go?

问题

在Go语言中,如果我有一个interface{}类型的变量,并将其编组(Marshal)为[]byte类型,然后再将其解组(Unmarshal)回interface{}类型,它应该保留原始的顺序。但实际情况并非如此。下面的程序演示了这个问题:

package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

func main() {
	var jd interface{}

	j := map[string]interface{}{
		"A": map[string]interface{}{"a": 1, "b": 2, "c": 3},
		"B": map[string]interface{}{"a": 1, "b": 2, "c": 3},
		"C": map[string]interface{}{
			"a": map[string]interface{}{"a": 1, "b": 2, "c": 3},
			"b": map[string]interface{}{"a": 1, "b": 2, "c": 3},
			"c": map[string]interface{}{"a": 1, "b": 2, "c": 3},
		},
	}

	s, _ := json.Marshal(j)
	_ = json.Unmarshal(s, &jd)

	fmt.Println(string(s))
	fmt.Println(j)
	fmt.Println(jd)
	if !reflect.DeepEqual(j, jd) {
		fmt.Println("Fail!")
	}
}

这个程序的结果是随机的,但下面是一个典型的结果:

{"A":{"a":1,"b":2,"c":3},"B":{"a":1,"b":2,"c":3},"C":{"a":{"a":1,"b":2,"c":3},"b":{"a":1,"b":2,"c":3},"c":{"a":1,"b":2,"c":3}}}
map[B:map[a:1 b:2 c:3] C:map[c:map[a:1 b:2 c:3] a:map[b:2 c:3 a:1] b:map[a:1 b:2 c:3]] A:map[c:3 a:1 b:2]]
map[A:map[a:1 b:2 c:3] B:map[a:1 b:2 c:3] C:map[b:map[c:3 a:1 b:2] c:map[a:1 b:2 c:3] a:map[a:1 b:2 c:3]]]
Fail!

可以看到,值在编组时保持了原始的顺序,但在解组时却是随机的(多次运行该程序会产生不同的结果)。结果是每次(到目前为止)都会导致DeepEqual比较失败。

这是Go语言的一个bug吗?有没有人可以提供解决方法?

英文:

It seems that if I have an interface{} in Go in a particular order and I Marshal it into a []byte and then Unmarshal it back into an interface{}, it should retain the original order. It does not. The result is that DeepEqual fails to match the two as you can see in the program below.

package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

func main() {
	var jd interface{}

	j := map[string]interface{}{
		"A": map[string]interface{}{"a": 1, "b": 2, "c": 3},
		"B": map[string]interface{}{"a": 1, "b": 2, "c": 3},
		"C": map[string]interface{}{
			"a": map[string]interface{}{"a": 1, "b": 2, "c": 3},
			"b": map[string]interface{}{"a": 1, "b": 2, "c": 3},
			"c": map[string]interface{}{"a": 1, "b": 2, "c": 3},
		},
	}

	s, _ := json.Marshal(j)
	_ = json.Unmarshal(s, &jd)

	fmt.Println(string(s))
	fmt.Println(j)
	fmt.Println(jd)
	if !reflect.DeepEqual(j, jd) {
		fmt.Println("Fail!")
	}
}

The results from this program are random, but this is a typical result:

{"A":{"a":1,"b":2,"c":3},"B":{"a":1,"b":2,"c":3},"C":{"a":{"a":1,"b":2,"c":3},"b":{"a":1,"b":2,"c":3},"c":{"a":1,"b":2,"c":3}}}

map[B:map[a:1 b:2 c:3] C:map[c:map[a:1 b:2 c:3] a:map[b:2 c:3 a:1] b:map[a:1 b:2 c:3]] A:map[c:3 a:1 b:2]]

map[A:map[a:1 b:2 c:3] B:map[a:1 b:2 c:3] C:map[b:map[c:3 a:1 b:2] c:map[a:1 b:2 c:3] a:map[a:1 b:2 c:3]]]

Fail!

As you can see, the values Marshal into the original order, but Unmarshal into a random order (multiple runs of this program will produce different results). The result is that the DeepEqual comparison fails every time (so far).

Is this a bug in Go? Does anyone have a workaround that they can suggest?

答案1

得分: 5

以下是翻译好的内容:

> Go编程语言规范
>
> For语句
>
> 对于映射(maps)的迭代顺序没有指定,并且不能保证在每次迭代中都相同。

按设计,映射(maps)的迭代顺序是伪随机的。

英文:

> The Go Programming Language
> Specification

>
> For statements
>
> The iteration order over maps is not specified and is not guaranteed
> to be the same from one iteration to the next.

By design, the iteration order over maps is pseudorandom.

答案2

得分: 3

地图的顺序不是导致它们不相等的原因。(如果你解组两次,你会得到两个深度相等的地图,但它们的顺序仍然随机不同。)

解组 JSON 数字时使用 float64:

float64,用于 JSON 数字

如果你将代码更改如下,它将起作用:

var num float64 = 0;
j := map[string]interface{}{
    "A": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
    "B": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
    "C": map[string]interface{}{
        "a": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
        "b": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
        "c": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
    },
}

然后你可以将 num 的类型更改为其他任何类型,它都会失败。

英文:

The order of the map isn't why it is not equal. (If you unmarshall twice you will get two deeply equal maps that still differ randomly in order.)

Unmarshalling a json number is float64:

float64, for JSON numbers

It will work if you change your code as follows:

var num float64 = 0;
j := map[string]interface{}{
    "A": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
    "B": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
    "C": map[string]interface{}{
        "a": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
        "b": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
        "c": map[string]interface{}{"a": num+1, "b": num+2, "c": num+3},
    },
}

You can then change the type of num to anything else and it will fail.

huangapple
  • 本文由 发表于 2015年4月25日 08:29:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/29859625.html
匿名

发表评论

匿名网友

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

确定