英文:
Golang: reflect.DeepEqual returns false
问题
我好的,以下是翻译好的代码:
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(p, want) {
log.Printf("returned %+v, want %+v", p, want)
}
}
希望对你有帮助!
英文:
I'm curious why this DeepEqual check is false:
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)
}
}
答案1
得分: 8
这是我的案例:
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 []
看起来 got
和 want
都是空的 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
英文:
Here is my case:
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)
}
})
}
}
When I run this test firstly, I got below message:
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
Take care this message:
GoogleAccountRepository.FindByClientCustomerIds() = [], want []
It seems got
and want
are all empty slice
, right? No, after I add below code:
fmt.Printf("got = %#v, want = %#v\n", got, tt.want)
It print out:
got = []cedar.GoogleAccount(nil), want = []cedar.GoogleAccount{}
As you can see, got
is not deep equal want
.
That's because I declare the googleAccounts
variable in googleAccountRepo.FindByClientCustomerIds
method like this:
var googleAccounts []cedar.GoogleAccount
After I change it to
var googleAccounts = make([]cedar.GoogleAccount, 0)
The test pass:
=== 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
得分: 2
DeepEqual检查两个条件是否相同:相同的类型和相同的值。
这里有一个棘手的情况,想象一下一个将值分配给any type
(接口)的场景,例如map[string]interface{}
,我们大多数时候会使用数据编码器/解码器(json)处理这些值。
场景1
package main
import (
"log"
"reflect"
)
func main() {
// 场景1
log.Print("场景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("返回了 %+v,期望是 %+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() {
// 场景2
log.Print("场景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("返回了 %+v,期望是 %+v", m1, m2)
}
}
2009/11/10 23:00:00 返回了 map[length:1],期望是 map[length:1]
在这些动态值的情况下谨慎使用DeepEqual API,可能需要将其转换为单一数据类型,或者始终尝试使用相同的结构(如果可能的话)。
https://play.golang.org/p/SBZ6T5aOPQO
英文:
DeepEqual checks 2 criterias identical types, identical values,
Here is a tricky case, think about a scenarios that's values are assigning to any type
(interfaces) ex: map[string]interface{}
most of the time we deal with these values with data encoders/decoders (json)
Scenario 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 returned map[length:1], want map[length:1]
With logs the issue will be hard to debug, since the values look the same unless we check the types (reflect.TypeOf(interface))
Scenario 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 returned map[length:1], want map[length:1]
Using DeepEqual API in these dynamic value scenarios should be done carefully, might need to convert in a single data type or always try to use the same structure if it's possible.
答案3
得分: 0
我认为这是一个编辑错误。我猜你想要编写的代码是:
"reflect.DeepEqual(p, want)"
但实际上你写成了:
"reflect.DeepEqual(input, want)"
英文:
I think it is an editing mistake.I guess that What you want to code is:
"reflect.DeepEqual(p, want)"
but you actually wrote:
"reflect.DeepEqual(input, want)"
答案4
得分: -2
DeepEqual
返回false,因为你正在比较两个不可比较的类型的实例。类型ResultResponse
不可比较,因为它的所有字段都不可比较。Result
字段是一个切片,而根据语言规定,切片是不可比较的。
英文:
DeepEqual
returns false because you're comparing two instances of a type which is not comparable. Type ResultResponse
is not comparable because not all of its fields are comparable. The Result
field is a slice and slices are specified by the language to be not comparable.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论