文档:https://pkg.go.dev/github.com/google/go-cmp/cmp
与reflect.DeepEqual 相比,它提供了自定义比较方式,另外如果是在测试中,它可以返回可读性较高的两个值之间的差异。
Func
// Diff返回一个人类可读的关于两个值之间差异的报告:y - x。// 当且仅当Equal对相同的输入值和选项返回true时,它返回一个空字符串。func Diff(x, y interface{}, opts ...Option) string// 它的行为与reflect.DeepEqual比较类似// 基本数据类型,如bool,int,float,complex numbers,string, channel 相当于 '=='// Func 只有两者都是 nil 时相等// Struct 递归判断每个字段Equal,如果包含未导出字段且没有忽略它,或导致恐慌// Slice 相同索引处的元素“深度”相等, non-nil 和 nil slice不相等// Map key 指向的value 相等, non-nil 和 nil map不相等// Pointer 两者存储的具体值“深度”相等func Equal(x, y interface{}, opts ...Option) bool
package mainimport ("fmt""github.com/google/go-cmp/cmp")type Persion struct {Name stringAge uint}func main() {p1 := Persion{"zhangsan",10}p2 := Persion{"zhangsan",20}diff := cmp.Diff(p1,p2)fmt.Println(diff)}--------------------------------output-----------------------------------main.Persion{Name: "zhangsan",- Age: 10,+ Age: 20,}
type Option
func AllowUnexported(types ...interface{}) Option // 允许比较指定的未导出类型func Exporter(f func(reflect.Type) bool) Option // 允许对哪些未导出字段进行比较/*// 允许对所有未导出字段进行比较diff := cmp.Diff(p1,p2,cmp.Exporter(func(r reflect.Type) bool {return true}))*/func Comparer(f interface{}) Option // 自定义比较器,f必须是 func(T, T) bool 类型func Ignore() Option // 不进行比较// FilterPath返回一个新的Option,只有f返回true时,opt才会生效// 传入的选项可以是Ignore、Transformer、Comparer、Options或先前过滤过的optionfunc FilterPath(f func(Path) bool, opt Option) Option
type Path
type Path []PathStepfunc (pa Path) GoString() string // 使用Go语法返回特定节点的路径func (pa Path) Index(i int) PathStepfunc (pa Path) Last() PathStepfunc (pa Path) String() string
type PathStep
type PathStep interface {String() stringType() reflect.TypeValues() (vx, vy reflect.Value)}
一个复杂的例子
func main() {p1 := NewPersion("zhangsan",10)p2 := NewPersion("zhangsan",20)// 当匹配到指定的path,我们将其转交给cmp.Comparer 做比较diff := cmp.Diff(p1,p2,cmp.FilterPath(func(path cmp.Path) bool {fmt.Println(path.String())fmt.Println(path.Last().String())fmt.Println(path.GoString())if path.String() == "Age" {return true}return false},cmp.Comparer(func(x,y uint) bool {return true})))fmt.Println(diff)}--------------------------------output-----------------------------------Name.Name{main.Persion}.NameAge.Age{main.Persion}.Age
