我在reflect.DeepEqual中遇到了一些奇怪的行为。我有一个map[string][]string类型的对象,其中一个键的值是一个空片段。当我使用gob对这个对象进行编码,然后将其解码为另一个映射时,根据reflect.DeepEqual,这两个映射并不相等(尽管内容是相同的)。
package main
import (
"fmt"
"bytes"
"encoding/gob"
"reflect"
)
func main() {
m0 := make(map[string][]string)
m0["apple"] = []string{}
// Encode m0 to bytes
var network bytes.Buffer
enc := gob.NewEncoder(&network)
enc.Encode(m0)
// Decode bytes into a new map m2
dec := gob.NewDecoder(&network)
m2 := make(map[string][]string)
dec.Decode(&m2)
fmt.Printf("%t\n", reflect.DeepEqual(m0, m2)) // false
fmt.Printf("m0: %+v != m2: %+v\n", m0, m2) // they look equal to me!
}输出:
false
m0: map[apple:[]] != m2: map[apple:[]]几个跟踪实验中的笔记:
如果我将m0["apple"]的值设置为非空片(例如m0["apple"] = []string{"pear"} ),那么DeepEqual返回true。
如果将值保留为空片,但从零开始构造相同的映射,而不是使用gob,则DeepEqual返回true:
m1 := make(map[string][]string)
m1["apple"] = []string{}
fmt.Printf("%t\n", reflect.DeepEqual(m0, m1)) // true!因此,严格地说,DeepEqual如何处理空片并不是一个问题;它与gob的序列化之间存在一些奇怪的交互。
发布于 2018-06-06 15:42:03
这是因为您编码了一个空的片,在解码过程中,encoding/gob包只在提供的(要解码的目标)不足以容纳编码值的情况下分配一个片。这记录在:gob:类型和值:上。
通常,如果需要分配,解码器将分配内存。否则,它将用从流中读取的值更新目标变量。
由于有0种编码元素,而且nil片完全能够容纳0种元素,所以不会分配任何切片。如果我们将切片与nil的比较结果打印出来,我们就可以验证这一点。
fmt.Println(m0["apple"] == nil, m2["apple"] == nil)上面的输出是(在围棋游乐场上尝试一下):
true false请注意,fmt包以相同的方式打印nil切片值和空片:作为[],您不能依赖其输出来判断切片是否为nil。
reflect.DeepEqual()对一个nil片和一个空的但非nil的片进行不同的处理(非深度相等):
请注意,非零空片和零片(例如,[]字节{}和[]字节( nil ))并不完全相等。
https://stackoverflow.com/questions/50724254
复制相似问题