Golang:reflect.DeepEqual返回false

时间:2015-04-02 21:15:20

标签: go

我很好奇为什么这个DeepEqual检查是错误的:

package main

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

type Result struct {
    Topic string `json:"topic,omitempty"`
    Id    int    `json:"id,omitempty"`
}

// Result represents the returned collection from a topic search.
type ResultResponse struct {
    Result []Result `json:"results"`
}

func main() {
    want := ResultResponse{
        []Result{{Topic: "Clojure", Id: 1000}},
    }

    input := `{"results": [ {"topic": "Clojure", "id": 1000} ]}`
    p := ResultResponse{}

    err := json.NewDecoder(strings.NewReader(input)).Decode(&p)

    if err != nil {
        panic(err)
    }

    fmt.Println(p, want)

    if !reflect.DeepEqual(input, want) {
        log.Printf("returned %+v, want %+v", p, want)
    }


}

4 个答案:

答案 0 :(得分:0)

我认为这是一个编辑错误。我猜你要编码的是:

"reflect.DeepEqual(p, want)"

但你实际写道:

"reflect.DeepEqual(input, want)"

答案 1 :(得分:0)

这是我的情况:

func TestGoogleAccountRepository_FindByClientCustomerIds(t *testing.T) {
    type args struct {
        ids []int
    }
    tests := []struct {
        name    string
        args    args
        want    []cedar.GoogleAccount
        wantErr bool
    }{
        {
            name:    "should get client customer ids correctly",
            args:    args{ids: []int{9258066191}},
            want:    make([]cedar.GoogleAccount, 0),
            wantErr: false,
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := googleAccountRepo.FindByClientCustomerIds(tt.args.ids)
            if (err != nil) != tt.wantErr {
                t.Errorf("GoogleAccountRepository.FindByClientCustomerIds() error = %v, wantErr %v", err, tt.wantErr)
                return
            }

            fmt.Printf("got = %#v, want = %#v\n", got, tt.want)
            if !reflect.DeepEqual(got, tt.want) {
                t.Errorf("GoogleAccountRepository.FindByClientCustomerIds() = %+v, want %+v", got, tt.want)
            }
        })
    }
}

第一次运行此测试时,出现以下消息:

load env vars from local fs env file
=== RUN   TestGoogleAccountRepository_FindByClientCustomerIds
--- FAIL: TestGoogleAccountRepository_FindByClientCustomerIds (0.62s)
=== RUN   TestGoogleAccountRepository_FindByClientCustomerIds/should_get_client_customer_ids_correctly
got = []cedar.GoogleAccount(nil), want = []cedar.GoogleAccount{}
    --- FAIL: TestGoogleAccountRepository_FindByClientCustomerIds/should_get_client_customer_ids_correctly (0.62s)
        googleAccount_test.go:64: GoogleAccountRepository.FindByClientCustomerIds() = [], want []
FAIL

请谨慎处理此消息:

GoogleAccountRepository.FindByClientCustomerIds() = [], want []

似乎gotwant都是空的slice,对吗?不,在我添加以下代码后:

fmt.Printf("got = %#v, want = %#v\n", got, tt.want)

它打印出来:

got = []cedar.GoogleAccount(nil), want = []cedar.GoogleAccount{}

如您所见,got不等于want

那是因为我在googleAccounts方法中声明了googleAccountRepo.FindByClientCustomerIds变量,如下所示:

var googleAccounts []cedar.GoogleAccount

将其更改为

var googleAccounts = make([]cedar.GoogleAccount, 0)

测试通过:

=== RUN   TestGoogleAccountRepository_FindByClientCustomerIds
--- PASS: TestGoogleAccountRepository_FindByClientCustomerIds (0.46s)
=== RUN   TestGoogleAccountRepository_FindByClientCustomerIds/should_get_client_customer_ids_correctly
got = []cedar.GoogleAccount{}, want = []cedar.GoogleAccount{}
    --- PASS: TestGoogleAccountRepository_FindByClientCustomerIds/should_get_client_customer_ids_correctly (0.46s)
PASS

Process finished with exit code 0

答案 2 :(得分:0)

DeepEqual 检查 2 个条件相同的类型、相同的

这是一个棘手的案例,考虑将值分配给 any type(接口)例如:map[string]interface{} 大部分时间我们使用数据编码器/解码器(json)处理这些值的场景

场景一

package main

import (
    "log"
    "reflect"
)

func main() {
    // Scenario 1
    log.Print("Scenario 1")
    m1 := make(map[string]interface{})
    m2 := make(map[string]interface{})

    m1["length"] = 1
    m2["length"] = 1.0
    if !reflect.DeepEqual(m1, m2) {
        log.Printf("returned %+v, want %+v", m1, m2)
    }
}

2009/11/10 23:00:00 返回 map[length:1],想要 map[length:1]

对于日志,这个问题将很难调试,因为除非我们检查类型,否则值看起来是一样的 (reflect.TypeOf(interface))

场景 2

package main

import (
    "encoding/json"
    "log"
    "reflect"
    "strings"
)

func main() {
    // Scenario 2
    log.Print("Scenario 2")
    m1 := make(map[string]interface{})
    m2 := make(map[string]interface{})
    
    str1 := `{"length": "1"}`
    str2 := `{"length": 1}`
    
    json.NewDecoder(strings.NewReader(str1)).Decode(&m1)
    json.NewDecoder(strings.NewReader(str2)).Decode(&m2)

    if !reflect.DeepEqual(m1, m2) {
        log.Printf("returned %+v, want %+v", m1, m2)
    }
}

2009/11/10 23:00:00 返回 map[length:1],想要 map[length:1]

在这些动态值场景中使用 DeepEqual API 应谨慎,可能需要转换为单一数据类型或尽可能尝试使用相同的结构

https://play.golang.org/p/SBZ6T5aOPQO

答案 3 :(得分:-2)

DeepEqual返回false,因为您正在比较两个不具有可比性的类型的实例。类型ResultResponse无法比较,因为并非所有字段都具有可比性。 Result字段是一个切片,切片由语言指定为不可比较。