Làm thế nào để so sánh nếu hai cấu trúc, lát hoặc bản đồ bằng nhau?


131

Tôi muốn kiểm tra xem hai cấu trúc, lát và bản đồ có bằng nhau không.

Nhưng tôi đang gặp vấn đề với đoạn mã sau. Xem ý kiến ​​của tôi tại các dòng có liên quan.

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


COnsider cũng 'hoạt động không hợp lệ: t2 == t1 (struct chứa map [string] int không thể so sánh được)', điều này xảy ra nếu struct không có int [] trong định nghĩa của anh ấy
Victor

Câu trả lời:


157

Bạn có thể sử dụng Refl.DeepEqual hoặc bạn có thể thực hiện chức năng của riêng mình (hiệu suất khôn ngoan sẽ tốt hơn so với sử dụng phản chiếu):

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

69

reflect.DeepEqual thường được sử dụng không chính xác để so sánh hai như cấu trúc, như trong câu hỏi của bạn.

cmp.Equal là một công cụ tốt hơn để so sánh các cấu trúc.

Để xem lý do tại sao sự phản chiếu không được khuyến khích, chúng ta hãy xem tài liệu :

Các giá trị cấu trúc là bằng nhau sâu sắc nếu các trường tương ứng của chúng, cả xuất và không xuất, đều bằng nhau sâu sắc.

....

số, bools, chuỗi và kênh - hoàn toàn bằng nhau nếu chúng bằng nhau khi sử dụng toán tử Go's ==.

Nếu chúng ta so sánh hai time.Timegiá trị của cùng một thời gian UTC, t1 == t2sẽ là sai nếu múi giờ siêu dữ liệu của chúng khác nhau.

go-cmptìm kiếm Equal()phương pháp và sử dụng phương pháp đó để so sánh chính xác thời gian.

Thí dụ:

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

9
Đúng chính xác! Khi viết bài kiểm tra, nó rất quan trọng để sử dụng go-cmpvà không reflect.
Kevin Minehart

Thật không may, không phản ánh hay cmp làm việc để so sánh một cấu trúc với một lát con trỏ với các cấu trúc. Nó vẫn muốn con trỏ giống nhau.
Violaman

2
@GeneralLeeSpeaking điều đó không đúng. Từ tài liệu cmp : "Con trỏ bằng nhau nếu các giá trị cơ bản mà chúng trỏ đến cũng bằng nhau"
Ilia Choly

Theo tài liệu cmp , chỉ nên sử dụng cmp khi viết bài kiểm tra, bởi vì nó có thể hoảng loạn nếu các đối tượng không thể so sánh được.
martin

17

Đây là cách bạn cuộn chức năng của riêng mình 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
Tôi khuyên bạn nên thêm if len(a.Z) != len(b.Z) || len(a.M) != len(b.M) { return false }, vì một trong số chúng có thể có thêm các trường.
OneOfOne

Tất cả các thông tin cấu trúc được biết đến tại thời điểm biên dịch. Thật xấu hổ khi trình biên dịch không thể thực hiện việc nâng vật nặng này theo một cách nào đó.
Rick-777

3
@ Rick-777 đơn giản là không có so sánh được xác định cho các lát. Đây là cách các nhà thiết kế ngôn ngữ muốn nó được. Thật không đơn giản để định nghĩa như so sánh các số nguyên đơn giản. Các lát có bằng nhau không nếu chúng chứa các phần tử giống nhau theo cùng một thứ tự? Nhưng nếu năng lực của họ khác nhau thì sao? Vv
justinas

1
if & a == & b {return true} Điều này sẽ không bao giờ đánh giá là đúng nếu các tham số để so sánh được truyền theo giá trị.
Sean

4

Kể từ tháng 7 năm 2017 bạn có thể sử dụng cmp.Equalvới cmpopts.IgnoreFieldstùy chọn.

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
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.