İki yapı, dilim veya harita eşitse nasıl karşılaştırılır?


132

İki yapının, dilimlerin ve haritaların eşit olup olmadığını kontrol etmek istiyorum.

Ancak aşağıdaki kodla ilgili sorunlarla karşılaşıyorum. Yorumlarımı ilgili satırlarda görün.

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


Cnsider ayrıca 'geçersiz işlem: t2 == t1 (yapı [string] int içeren harita karşılaştırılamaz)', bu, yapının tanımında int [] yoksa olur
Victor

Yanıtlar:


158

Yansıtmayı kullanabilirsin.DeepEqual veya kendi işlevini uygulayabilirsin (hangi performans açısından yansıtma kullanmaktan daha iyi olurdu):

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

71

reflect.DeepEqual Sorunuzdaki gibi iki benzer yapıyı karşılaştırmak için genellikle yanlış kullanılır.

cmp.Equal yapıları karşılaştırmak için daha iyi bir araçtır.

Düşüncenin neden yanlış olduğunu görmek için belgelere bakalım :

Struct değerleri, hem dışa aktarılan hem de dışa aktarılmayan karşılık gelen alanları büyük ölçüde eşitse derinden eşittir.

....

sayılar, bool'lar, dizeler ve kanallar - Go'nun == operatörü kullanılarak eşitlerse derinden eşittir.

time.TimeAynı UTC zamanına ait iki değeri karşılaştırırsak t1 == t2, meta veri saat dilimleri farklıysa yanlış olur.

go-cmpEqual()yöntemi arar ve zamanları doğru şekilde karşılaştırmak için kullanır.

Misal:

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

10
Evet kesinlikle! Test yazarken kullanmak go-cmpve kullanmamak çok önemlidir reflect.
Kevin Minehart

Ne yazık ki, bir yapıyı bir dilim işaretçilerle yapılarla karşılaştırmak için ne yansıtır ne de cmp çalışır. Yine de işaretçilerin aynı olmasını istiyor.
Violaman

2
@GeneralLeeSpeaking bu doğru değil. Gönderen cmp belgelerinde : "Onlar işaret altında yatan değerleri de eşit eğer İşaretçiler eşittir"
Ilia Choly

Göre cmp belgelerine testleri yazarken nesneler karşılaştırılabilir değilse o panik çünkü, cmp kullanarak, sadece tavsiye edilir.
martin

17

Kendi işlevinizi şu şekilde döndürebilirsiniz: 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
Eklemenizi tavsiye ederim if len(a.Z) != len(b.Z) || len(a.M) != len(b.M) { return false }çünkü bunlardan birinde fazladan alanlar olabilir.
OneOfOne

Tüm yapısal bilgiler derleme zamanında bilinir. Derleyicinin bu ağır işi bir şekilde yapamaması utanç verici.
Rick-777

3
@ Rick-777 dilimler için tanımlanmış bir karşılaştırma yoktur. Dil tasarımcıları böyle olmasını istediler. Diyelim ki basit tam sayıların karşılaştırılması kadar basit değil. Aynı sırada aynı öğeleri içeriyorlarsa dilimler eşit midir? Peki ya kapasiteleri farklıysa? Vb
justinas

1
if & a == & b {dönüş doğru} Karşılaştırılacak parametreler değere göre aktarılıyorsa bu hiçbir zaman doğru olarak değerlendirilmez.
Sean

4

Yana Temmuz 2017 kullanabilirsiniz cmp.Equalile cmpopts.IgnoreFieldsseçeneğiyle.

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
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.