如何在最近的Go weekly中比较两个函数的指针相等性?
在Go中,有没有办法比较两个非nil函数指针以测试相等性?我的平等标准是指针平等。如果不允许,是否有任何特殊原因导致不允许指针相等 到目前为止,如果我尝试以直截了当的方式进行此操作:如何在最近的Go weekly中比较两个函数的指针相等性?,go,function-pointers,go-reflect,Go,Function Pointers,Go Reflect,在Go中,有没有办法比较两个非nil函数指针以测试相等性?我的平等标准是指针平等。如果不允许,是否有任何特殊原因导致不允许指针相等 到目前为止,如果我尝试以直截了当的方式进行此操作: package main import "fmt" func SomeFun() { } func main() { fmt.Println(SomeFun == SomeFun) } 我明白了 据我所知,这种行为是最近才出现的 我使用reflect软件包找到了答案;然而,Atom在下面指出,这实
package main
import "fmt"
func SomeFun() {
}
func main() {
fmt.Println(SomeFun == SomeFun)
}
我明白了
据我所知,这种行为是最近才出现的
我使用reflect软件包找到了答案;然而,Atom在下面指出,这实际上会产生未定义的行为。有关更多信息和可能的替代解决方案,请参见Atom的帖子
package main
import "fmt"
import "reflect"
func SomeFun() { }
func AnotherFun() { }
func main() {
sf1 := reflect.ValueOf(SomeFun)
sf2 := reflect.ValueOf(SomeFun)
fmt.Println(sf1.Pointer() == sf2.Pointer())
af1 := reflect.ValueOf(AnotherFun)
fmt.Println(sf1.Pointer() == af1.Pointer())
}
产出:
true
false
现在不允许进行映射和函数值比较(除了
根据Go 1计划,与nil进行比较。函数相等是
在某些上下文中有问题,映射相等比较指针,而不是
地图的内容
函数相等在闭包存在时是有问题的(当
两个闭包相等吗?)
解决方法取决于具体情况。我不得不改变几个比较函数的地方。有一次,我只是做了一些不同的事情,所以我不需要再比较它们了。在另一个例子中,我使用一个struct将函数与可比较的字符串相关联,比如
type nameFunc struct {
name string
fval func()
}
我只需要比较两个函数,因此最简单的方法是保留这些结构的一个片段,并根据需要扫描该片段,比较name字段并分派fval。如果你有很多,你可以用地图代替。如果函数具有不同的签名,则可以使用接口,依此类推。请注意,等式和标识之间存在差异。运算符
==
和=正在比较等价值(比较通道时除外),而不是标识值。因为这些运算符试图不混合相等和标识,所以Go1在这方面比前Go1更一致
函数相等不同于函数恒等式
不允许==
和的一个原因=函数类型上的代码>是性能。例如,以下闭包未使用其环境中的任何变量:
f := func(){fmt.Println("foo")}
不允许比较函数使编译器能够为闭包生成单个实现,而不需要运行时(在运行时)创建新的闭包。因此,从性能的角度来看,不允许函数比较的决定是一个好的决定
关于使用reflect
包确定函数标识,代码如下
func SomeFun() {}
func AnotherFun() {}
func main() {
sf1 := reflect.ValueOf(SomeFun)
sf2 := reflect.ValueOf(SomeFun)
fmt.Println(sf1.Pointer() == sf2.Pointer()) // Prints true
af1 := reflect.ValueOf(AnotherFun)
fmt.Println(sf1.Pointer() == af1.Pointer()) // Prints false
}
依赖于未定义的行为。对于程序将打印什么,没有任何保证。编译器可能决定将SomeFun
和另一个fun
合并到一个实现中,在这种情况下,第二个print语句将打印true
。事实上,绝对不能保证第一个print语句将打印true
(它可能在其他一些Go1编译器和运行时下打印false
)
对原始问题的正确答案是:
package main
import "fmt"
func F1() {}
func F2() {}
var F1_ID = F1 // Create a *unique* variable for F1
var F2_ID = F2 // Create a *unique* variable for F2
func main() {
f1 := &F1_ID // Take the address of F1_ID
f2 := &F2_ID // Take the address of F2_ID
// Compare pointers
fmt.Println(f1 == f1) // Prints true
fmt.Println(f1 == f2) // Prints false
}
我认为这并不能真正回答我的问题。我知道我使用的方式不允许进行函数值比较;我想知道的是是否有任何解决办法。我还想知道为什么函数指针相等有问题。@BurntSushi5这是个好问题。当然,有些语言确实有闭包,您可以在其中比较函数指针。在这些语言中,在不同变量上关闭的同一函数的闭包测试结果并不相等。这似乎只是在回避代表权问题。这在围棋中是不允许的,没有根本的根本原因。它可以以明智、可靠和一致的方式实施;他们只是选择不这样做。@peterSO回应您的编辑:这并不能真正回答为什么不能使用函数指针相等。如果两个函数指针指向相同的内存位置,那么它们应该相等。它不会像函数相等的一般形式那样有用,但也不会无用。@tchrist我完全理解。然而,我要问的是指针相等。那里不应该有任何肮脏的封闭;两个函数指针是否指向同一内存位置。它不像你所建议的那么复杂,但它确实有点意思。reflect软件包就是我想要的。我已经用答案更新了我的OP。太好了。我也通过改变我的方法来解决这个问题。感谢您提供有关保留函数的字符串表示形式的提示。对于我正在做的事情(允许在库中使用任意回调函数),它不会很好地工作,但它可能会很有用。我已经用答案更新了我的OP。反应很好。非常感谢。你回答“为什么”肯定会得到表扬,但我对你对我最初问题的回答感到困惑。它似乎在测试变量F1_ID和F2_ID的标识,而不是函数F1和F2的标识。例如,如果我有'var F1_ID2=F1',那么如果我们测试函数标识,&F1_ID==&F1_ID2将返回true;但结果是错误的。而且,你对我使用reflect的方法的批评让我担心。你不是在暗示在Go中测试函数标识是不可能保证的吗?注释1:最后一段代码中的假设是某个特定函数有一个ID。注释2:reflect
包不是语言规范的一部分,因此,使用它不能保证函数标识,但是Pointer()
方法确实在当前实现中工作得很好Go1中的函数没有标识,因此编译器没有义务跟踪函数标识。我想说的是,语言规范意味着,如果
package main
import "fmt"
func F1() {}
func F2() {}
var F1_ID = F1 // Create a *unique* variable for F1
var F2_ID = F2 // Create a *unique* variable for F2
func main() {
f1 := &F1_ID // Take the address of F1_ID
f2 := &F2_ID // Take the address of F2_ID
// Compare pointers
fmt.Println(f1 == f1) // Prints true
fmt.Println(f1 == f2) // Prints false
}