douyan1321 2012-03-10 01:42
浏览 143
已采纳

如何在最新的Go周刊中比较两个函数的指针相等性?

In Go, is there any way to compare two non-nil function pointers to test for equality? My standard of equality is pointer equality. If not, is there any particular reason why pointer equality is not allowed?

As of now, if I attempt to do this in the straight-forward way:

package main

import "fmt"

func SomeFun() {
}

func main() {
    fmt.Println(SomeFun == SomeFun)
}

I get

./func-pointers.go:12: invalid operation: SomeFun == SomeFun (func can only be compared to nil)

It is my understanding that this behavior was introduced recently.


I've found an answer using the reflect package; however Atom suggests below that this actually produces undefined behavior. See Atom's post for more info and a possible alternative solution.

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())
}

Outputs:

true
false
  • 写回答

3条回答 默认 最新

  • doushui5587 2012-03-10 07:40
    关注

    Note that there is a difference between equality and identity. The operators == and != in Go1 are comparing the values for equivalence (except when comparing channels), not for identity. Because these operators are trying not to mix equality and identity, Go1 is more consistent than pre-Go1 in this respect.

    Function equality is different from function identity.


    One reason for not allowing == and != on function types is performance. For example, the following closure is not using any variables from its environment:

    f := func(){fmt.Println("foo")}
    

    Disallowing comparisons of functions enables the compiler to generate a single implementation for the closure, instead of requiring the run-time to create a new closure (at run-time). So, from performance viewpoint the decision to disallow function comparisons was a good decision.


    In relation to using the reflect package to determine function identity, a code like

    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
    }
    

    relies on undefined behavior. There are no guarantees as to what the program will print. The compiler may decide that it will merge SomeFun and AnotherFun into a single implementation, in which case the 2nd print statement would print true. In fact, there is absolutely no guarantee that the 1st print statement will print true (it may, under some other Go1 compiler and run-time, print false).


    A correct answer to your original question is:

    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
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!