如何比较struct,slice,map是否相等?

时间:2014-07-02 14:41:07

标签: go go-reflect

我想检查两个结构是否相等,但有一些问题:

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

6 个答案:

答案 0 :(得分:116)

您可以使用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))

答案 1 :(得分:36)

reflect.DeepEqual经常被错误地用来比较两个类似的结构,就像你的问题一样。

cmp.Equal是比较结构的更好工具。

要了解为何反思不明智,请查看documentation

  

如果导出和未导出的相应字段非常相等,则结构值非常相等。

     

...

     

数字,bools,字符串和通道 - 如果使用Go' = =运算符相等则非常相等。

如果我们比较相同UTC时间的两个time.Time值,如果他们的元数据时区不同,则t1 == t2将为false。

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

答案 2 :(得分:15)

以下是您如何推广自己的功能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
}

答案 3 :(得分:7)

July 2017起,您可以将cmp.Equalcmpopts.IgnoreFields选项一起使用。

func TestPerson(t *testing.T) {
    type person struct {
        ID   int
        Name string
    }

    p1 := person{ID: 1, Name: "john doe"}
    p2 := person{ID: 2, Name: "john doe"}
    println(cmp.Equal(p1, p2))
    println(cmp.Equal(p1, p2, cmpopts.IgnoreFields(person{}, "ID")))

    // Prints:
    // false
    // true
}

答案 4 :(得分:1)

如果要在单元测试中进行比较,可以方便地选择EqualValues中的testify函数。

答案 5 :(得分:1)

如果你想比较简单的一级结构,最好和最简单的方法是 if 语句。

像这样if s1 == s2

这是一个简单的例子:

type User struct { 
    name      string 
    email           string
} 

func main() {
    u1 := User{
            name: "Iron Man", 
            email: "ironman@avengers.com",
    }
    u2 := User{
            name: "Iron Man", 
            email: "ironman@avengers.com",
    }
        // Comparing 2 structs
        if u1 == u2 {
            fmt.Println("u1 is equal to u2")
        } else {
            fmt.Println("u1 is not equal to u2")
        }
}

结果:u1 is equal to u2

你可以玩这个here