如何在Go中实现Python的mock.ANY功能?
在Go中用cmp包实现类似Python mock.ANY的字典字段忽略匹配
在比较字典时忽略指定字段的值,Python里用mock.ANY就能轻松实现,示例代码如下:
from unittest.mock import ANY actual = {'userName':'bob', 'lastModified':'2012-01-01'} expected = {'userName':'bob', 'lastModified': ANY} assert actual == expected
我尝试用Go的cmp包(支持自定义Equal方法)实现同样的功能,但代码跑不起来。问题应该是自定义的MatchAll类型没法和string类型正常匹配,求解决办法?我的尝试代码如下:
package main import ( "fmt" "github.com/google/go-cmp/cmp" ) type MatchAll string func (m MatchAll) Equal(v string) bool { return true } func main() { matchAll := MatchAll("bruh") actual := map[string]any{ "key": matchAll, } expected := map[string]any{ "key": "foobar", } fmt.Println(cmp.Equal(expected, actual)) }
解决办法
问题核心是cmp包的Equal方法是双向匹配的,你定义的MatchAll的Equal方法只处理了和string的单向比较,而且字典value是any类型时,cmp不会自动处理跨类型的匹配逻辑。正确的做法是用cmp.Option自定义比较规则,或者给MatchAll实现通用的Equal方法。
方案一:自定义比较器(Comparer)
package main import ( "fmt" "github.com/google/go-cmp/cmp" ) // 标记类型,表示匹配任意值 type MatchAll struct{} // 自定义比较器:只要其中一个值是MatchAll,就判定为相等 func matchAny(v1, v2 any) bool { _, isMatch1 := v1.(MatchAll) _, isMatch2 := v2.(MatchAll) return isMatch1 || isMatch2 } func main() { actual := map[string]any{ "userName": "bob", "lastModified": "2012-01-01", } expected := map[string]any{ "userName": "bob", "lastModified": MatchAll{}, } // 传入自定义比较器作为cmp的选项 fmt.Println(cmp.Equal(expected, actual, cmp.Comparer(matchAny))) // 输出true }
方案二:给MatchAll实现通用Equal方法
如果把MatchAll定义为导出类型(首字母大写),可以直接实现Equal方法让cmp识别:
package main import ( "fmt" "github.com/google/go-cmp/cmp" ) // 导出的MatchAll类型,用于匹配任意值 type MatchAll struct{} // Equal方法:匹配任意类型的值都返回true func (m MatchAll) Equal(_ any) bool { return true } func main() { actual := map[string]any{ "userName": "bob", "lastModified": "2012-01-01", "age": 30, } expected := map[string]any{ "userName": "bob", "lastModified": MatchAll{}, "age": MatchAll{}, } // 因为MatchAll是导出类型,无需额外配置即可生效 fmt.Println(cmp.Equal(expected, actual)) // 输出true }
如果是未导出类型,需要加上cmp.AllowUnexported(MatchAll{})作为选项传入cmp.Equal。
内容的提问来源于stack exchange,提问作者Dracula
相关产品推荐
相关产品推荐

