【问题标题】:Golang: reflect.DeepEqual returns falseGolang:reflect.DeepEqual 返回 false
【发布时间】:2015-04-02 21:15:20
【问题描述】:

我很好奇为什么这个 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)
    }


}

【问题讨论】:

标签: go


【解决方案1】:

这是我的情况:

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

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

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】:

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

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

    场景 1

    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】:

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

      "reflect.DeepEqual(p, want)"
      

      但你实际上写道:

      "reflect.DeepEqual(input, want)"
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 不正确,问题是 DeepEqual 的第一个参数是 string 类型(可能是由于拼写错误)。 DeepEqual 被记录为能够处理切片和递归类型。
        猜你喜欢
        • 2019-09-10
        • 2019-06-27
        • 1970-01-01
        • 1970-01-01
        • 2014-10-18
        • 2015-08-02
        • 2012-05-17
        • 2013-10-26
        • 2013-01-06
        相关资源
        最近更新 更多