英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论