2014-07-02 16 views
49

Ich möchte, dass zwei structs gleich sind zu überprüfen, haben aber ein Problem:Wie struct, slice, map vergleichen sind gleich?

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

+0

Beachten Sie auch 'ungültige Operation: t2 == t1 (struct enthält map [string] int nicht verglichen werden kann)', geschieht dies, wenn die Struktur nicht int [] innerhalb seiner Definition hat – Victor

Antwort

79

Sie reflect.DeepEqual verwenden können, oder Sie können Ihre eigene Funktion (die Leistung klug wäre besser realisieren als mit Reflexion):

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)) 
12

Hier ist, wie Sie Ihre eigene Funktion 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

Ich würde empfehlen, 'if len (aZ)! = Len (bZ) || hinzuzufügen len (a.M)! = len (b.M) {return false} ', weil einer von ihnen zusätzliche Felder haben könnte. – OneOfOne

+1

Hier ist meine Version von diesem: http://play.golang.org/p/mzvvoksjDq – OneOfOne

+0

@OneOfOne Ich denke, Sie haben den falschen Link gepostet. –

7

reflect.DeepEqual häufig verwendet, rollen würden fälschlicherweise zwei wie structs zu vergleichen, wie es in Ihrer Frage.

cmp.Equal ist ein besseres Werkzeug für den Vergleich von Strukturen.

Um zu sehen, warum Reflexion ist schlecht beraten, die am documentation sehen lassen:

Struct Werte sind tief gleich, wenn ihre entsprechenden Felder, sowohl exportiert und unexported, sind tief gleich.

....

Zahlen, bools, Strings und Kanäle - sind tief gleich, wenn sie gleich sind Gos == Operator.

Wenn wir zwei time.Time Werte derselben UTC-Zeit vergleichen, werden t1 == t2 falsch sein, wenn sie sind Metadaten Zeitzone unterscheidet.

go-cmp sucht nach der Equal() Methode und verwendet, um Zeiten korrekt zu vergleichen.

Beispiel:

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 
+1

Ja genau! Beim Schreiben von Tests ist es sehr wichtig, 'go-cmp' zu verwenden und nicht' reflect'. –