無論Go中元素的順序如何,如何在語義上比較結構與嵌套切片是一個常見問題。在Go語言中,結構體是一種聚合數據類型,而切片則是一種動態數組。php小編子墨將為您解答這個問題。在比較結構體時,只有當所有成員都是可比較的類型時,它們才是可比較的。而在比較嵌套切片時,我們需要逐級比較切片中的元素。如果切片的元素類型是不可比較的,我們需要使用遞歸方法來比較切片的每個元素。無論是結構體還是嵌套切片,我們都可以通過遍歷元素來比較它們。
問題內容
給出下一個類型結構定義:
type A struct { Id int Bs []B Sub C } type B struct { Id int Str string } type C struct { Id int Ds []D } type D struct { Id int Num int }
登錄后復制
我想測試 A 的接下來兩個實例在語義上是否相等,無論所有層次結構級別中切片元素的順序如何。
var want = &A{ Id: 1, Bs: []B{{Id: 10, Str: "b10"}, {Id: 20, Str: "b20"}}, Sub: C{ Id: 100, Ds: []D{{Id: 101, Num: 1001}, {Id: 102, Num: 1002}}, }, } var got = &A{ Id: 1, Bs: []B{{Id: 20, Str: "b20"}, {Id: 10, Str: "b10"}}, Sub: C{ Id: 100, Ds: []D{{Id: 102, Num: 1002}, {Id: 101, Num: 1001}}, }, }
登錄后復制
斷言比較應返回true
解決方法
包 cmp 旨在成為 reflect.DeepEqual
的更強大、更安全的替代品用于比較兩個值在語義上是否相等。
這里是語義相等結構比較的完整實現,無論切片元素在所有層次結構級別的順序如何。
文件source.go
package main type A struct { Id int Bs []B Sub C } type B struct { Id int Str string } type C struct { Id int Ds []D } type D struct { Id int Num int } func NewA() *A { return &A{ Id: 1, Bs: []B{{Id: 20, Str: "b20"}, {Id: 10, Str: "b10"}}, Sub: C{ Id: 100, Ds: []D{{Id: 102, Num: 1002}, {Id: 101, Num: 1001}}, }, } }
登錄后復制
文件source_test.go
package main import ( "fmt" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) var want = &A{ Id: 1, Bs: []B{{Id: 10, Str: "b10"}, {Id: 20, Str: "b20"}}, Sub: C{ Id: 100, Ds: []D{{Id: 101, Num: 1001}, {Id: 102, Num: 1002}}, }, } func TestNewA(t *testing.T) { got := NewA() less := func(x, y any) bool { switch xv := x.(type) { case B: yv := y.(B) return fmt.Sprintf("%d-%s", xv.Id, xv.Str) < fmt.Sprintf("%d-%s", yv.Id, yv.Str) case D: yv := y.(D) return fmt.Sprintf("%d-%d", xv.Id, xv.Num) < fmt.Sprintf("%d-%d", yv.Id, yv.Num) default: return false } } if diff := cmp.Diff(want, got, cmpopts.SortSlices(less)); diff != "" { t.Errorf("mismatch:\n%s", diff) } }
登錄后復制