Как сравнить struct, slice, map равны?
Я хочу проверить, что две структуры равны, но имеют некоторые проблемы:
package main
import (
"fmt"
"reflect"
)
type T struct {
X int
Y string
Z []int
M map[string]int
}
func main() {
t1 := T{
X:1,
Y:"lei",
Z:[]int{1,2,3},
M:map[string]int{
"a":1,
"b":2,
},
}
t2 := T{
X:1,
Y:"lei",
Z:[]int{1,2,3},
M:map[string]int{
"a":1,
"b":2,
},
}
fmt.Println(t2 == t1)
//error - invalid operation: t2 == t1 (struct containing []int cannot be compared)
fmt.Println(reflect.ValueOf(t2) == reflect.ValueOf(t1))
//false
fmt.Println(reflect.TypeOf(t2) == reflect.TypeOf(t1))
//true
//Update: slice or map
a1 := []int{1,2,3,4}
a2 := []int{1,2,3,4}
fmt.Println(a1==a2)
//invalid operation: a1 == a2 (slice can only be compared to nil)
m1 := map[string]int{
"a":1,
"b":2,
}
m2 := map[string]int{
"a":1,
"b":2,
}
fmt.Println(m1==m2)
// m1 == m2 (map can only be compared to nil)
}
http://play.golang.org/p/AZIzW2WunI
Ответы
Ответ 1
Вы можете использовать reflect.DeepEqual, или вы можете реализовать свою собственную функцию (эффективность которой будет лучше, чем использование рефлексии):
http://play.golang.org/p/CPdfsYGNy_
m1 := map[string]int{
"a":1,
"b":2,
}
m2 := map[string]int{
"a":1,
"b":2,
}
fmt.Println(reflect.DeepEqual(m1, m2))
Ответ 2
reflect.DeepEqual
часто неправильно используется для сравнения двух одинаковых структур, как в вашем вопросе.
cmp.Equal
- лучший инструмент для сравнения структур.
Чтобы понять, почему рефлексия опрометчива, давайте взглянем на документацию:
Значения структур сильно равны, если их соответствующие поля, как экспортированные, так и не экспортированные, глубоко совпадают.
....
числа, числа, строки и каналы - очень равны, если они равны, используя оператор Go ==.
Если мы сравним два значения time.Time
одного и того же времени UTC, то t1 == t2
будет ложным, если их часовой пояс метаданных отличается.
go-cmp
ищет метод Equal()
и использует его для правильного сравнения времени.
Пример:
m1 := map[string]int{
"a": 1,
"b": 2,
}
m2 := map[string]int{
"a": 1,
"b": 2,
}
fmt.Println(cmp.Equal(m1, m2)) // will result in true
Ответ 3
Вот как бы вы применили свою собственную функцию http://play.golang.org/p/Qgw7XuLNhb
func compare(a, b T) bool {
if &a == &b {
return true
}
if a.X != b.X || a.Y != b.Y {
return false
}
if len(a.Z) != len(b.Z) || len(a.M) != len(b.M) {
return false
}
for i, v := range a.Z {
if b.Z[i] != v {
return false
}
}
for k, v := range a.M {
if b.M[k] != v {
return false
}
}
return true
}
Ответ 4
Если вы сравниваете их в модульном тесте, удобной альтернативой является функция EqualValues в testify.