web-dev-qa-db-fra.com

Comment comparer struct, slice, map sont égaux?

Je veux vérifier que deux structures sont égales, mais ont un problème:

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

89
leiyonglin

Vous pouvez utiliser reflect.DeepEqual , ou vous pouvez implémenter votre propre fonction (quelle performance serait préférable à l’utilisation de la réflexion):

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))
126
OneOfOne

_reflect.DeepEqual_ est souvent utilisé à tort pour comparer deux structures identiques, comme dans votre question.

_cmp.Equal_ est un meilleur outil pour comparer les structures.

Pour voir pourquoi la réflexion est mal avisée, regardons le documentation :

Les valeurs de structure sont profondément égales si leurs champs correspondants, exportés et non exportés, sont profondément égaux.

....

les nombres, les booléens, les chaînes et les canaux sont profondément égaux s'ils sont égaux avec l'opérateur == de Go.

Si nous comparons deux valeurs _time.Time_ de la même heure UTC, _t1 == t2_ sera false si leur fuseau horaire de métadonnées est différent.

go-cmp recherche la méthode Equal() et l'utilise pour comparer correctement les temps.

Exemple:

_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
_
40
Cole Bittel

Voici comment vous pouvez créer votre propre fonction 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
}
14
Ilia Choly