在Go中正常使用函数变量允许它们仅与nil进行比较,而不是相互比较。这个原因(正如我已经解释过的那样)是因为Go有闭包,所以平等的定义是模糊的。如果我有两个不同的闭包,其中不同的值绑定到局部变量,但使用相同的底层函数,它们应该被认为是相等还是不相等?
然而,我做希望能够进行这样的比较。特别是,我有这样的代码(除了在我的实际代码中,检查实际上是必要的 - 这只是一个虚拟的例子),我将函数指针与函数文字进行比较:
func getFunc(which bool) (func ()) {
if which {
return func1
} else {
return func2
}
}
func func1() { }
func func2() { }
f := getFunc(true)
if f == func1 {
fmt.Println("func1")
} else {
fmt.Println("func2")
}
答案 0 :(得分:3)
您可以按名称比较功能:
f := getFunc(true)
f1 := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
f2 := runtime.FuncForPC(reflect.ValueOf(func1).Pointer()).Name()
if f1 == f2 {
fmt.Println("func1")
} else {
fmt.Println("func2")
}
但这依赖于reflect
和runtime
包。这样做可能不是一个好主意。
你真的需要比较功能吗?如果可能,我会考虑替代方案。
答案 1 :(得分:1)
如果您要比较的所有功能都具有相同的签名,您可以执行以下操作:
type cmpFunc struct {
f func()
id uint64
}
func (c *cmpFunc) call() { c.f() }
func (c *cmpFunc) equals(other *cmpFunc) { return c.id == other.id }
makeComparable(f func()) *cmpFunc {
return &cmpFunc{f, get_uniq_id()}
}
get_uniq_id
在框中所说的内容。这有点丑陋,因为Go没有()
重载,如果你想为一般的函数做这个,那么如果没有泛型,它或多或少是不可能的。但是这对你的目的应该很有效。
答案 2 :(得分:1)
根据@ Luke的回答,似乎我可以直接测试指针相等性。请注意,这真的很不对劲。引用reflect.Value.Pointer()
文档:
如果v的Kind是Func,则返回的指针是底层代码 指针,但不一定足以识别单个函数 唯一。唯一的保证是当且仅当结果为零时 v是一个零函数值。
那就是说,你可以做的就是:
f := getFunc(true)
f1 := reflect.ValueOf(f).Pointer()
f2 := reflect.ValueOf(func1).Pointer()
eq := f1 == f2
请注意,我确实对这个新版本运行了一系列测试(我曾用它来回归测试由@ Luke的答案产生的代码),并且它们全部通过,这让我相信发出的警告reflect
文档可以忽略不计,但是忽略文档确实不是一个好主意...