How to compare 2 functions in Go?

huangapple go评论82阅读模式
英文:

How to compare 2 functions in Go?

问题

例如,我有一个要比较的函数列表:

http://play.golang.org/p/_rCys6rynf

type Action func(foo string)

type Handler struct {
  Get Action
  Post Action
}

var routes map[string]Handler

func Undefined(foo string) {
}

func Defined(foo string) {
}

func init() {
  routes = map[string]Handler{
    `/`: Handler{Defined,Undefined},
  }
}

func main() {
  for _, handler := range routes {
    if handler.Post != Undefined { 
      // 做一些操作
    } // 无效操作:(func(string))(handler.Post) != Undefined(只能将函数与nil进行比较)

    if &handler.Post != &Undefined { 
      // 做一些操作
    } // 无法获取Undefined的地址
    // 无效操作:&handler.Post != &Undefined(类型不匹配:*Action和*func(string))
  }
}

如何正确比较两个函数是否相同?

英文:

For example I have list of functions that I want to compare:

http://play.golang.org/p/_rCys6rynf

type Action func(foo string)

type Handler struct {
  Get Action
  Post Action
}

var routes map[string]Handler

func Undefined(foo string) {
}

func Defined(foo string) {
}

func init() {
  routes = map[string]Handler{
    `/`: Handler{Defined,Undefined},
  }
}

func main() {
  for _, handler := range routes {
    if handler.Post != Undefined { 
      // do something
    } // invalid operation: (func(string))(handler.Post) != Undefined (func can only be compared to nil)


    if &handler.Post != &Undefined { 
      // do something 
    } // cannot take the address of Undefined
    // invalid operation: &handler.Post != &Undefined (mismatched types *Action and *func(string))
  }
}

What is the correct way to compare if two functions are the same?

答案1

得分: 20

在进一步之前,你应该进行重构,而不是比较函数值的地址。

规范:比较运算符:

> 切片、映射和函数值是不可比较的。然而,作为一个特例,切片、映射或函数值可以与预声明的标识符nil进行比较。

函数值是不可比较的。你可以比较函数值的地址是否相同(不是持有函数值的变量的地址,而是函数值本身的地址)。

你不能获取函数的地址,但是如果你使用fmt包打印它,它会打印出它的地址。所以你可以使用fmt.Sprintf()来获取函数值的地址。

看看这个例子(基于你的代码):

hand := &Handler{Undefined, Defined}
p1 := fmt.Sprintf("%v", Undefined)
p2 := fmt.Sprintf("%v", hand.Get)
fmt.Println("期望为true:", p1 == p2)

fmt.Println("期望为false:", fmt.Sprintf("%v", Defined) == fmt.Sprintf("%v", hand.Get))
fmt.Println("期望为true:", fmt.Sprintf("%v", Defined) == fmt.Sprintf("%v", hand.Post))

输出结果(在Go Playground上尝试):

期望为true: true
期望为false: false
期望为true: true

另一个选项是使用reflect.Value.Pointer()来获取函数值的地址,这正是fmt包所做的:fmt/print.go

func (p *pp) fmtPointer(value reflect.Value, verb rune) {
    // ...
    case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice,
            reflect.UnsafePointer:
        u = value.Pointer()
    // ...
}

但是你应该进行重构,而不是比较函数值的地址。

英文:

Before going further: you should refactor and not compare function value addresses.

Spec: Comparison operators:

> Slice, map, and function values are not comparable. However, as a special case, a slice, map, or function value may be compared to the predeclared identifier nil.

Function values are not comparable. What you may do is compare if the addresses of the function values are the same (not the address of variables holding function values, but the function values themselves).

You can't take the address of a function, but if you print it with the fmt package, it prints its address. So you can use fmt.Sprintf() to get the address of a function value.

See this example (based on your code):

hand := &Handler{Undefined, Defined}
p1 := fmt.Sprintf("%v", Undefined)
p2 := fmt.Sprintf("%v", hand.Get)
fmt.Println("Expecting true:", p1 == p2)

fmt.Println("Expecting false:", fmt.Sprintf("%v", Defined) == fmt.Sprintf("%v", hand.Get))
fmt.Println("Expecting true:", fmt.Sprintf("%v", Defined) == fmt.Sprintf("%v", hand.Post))

Output (try it on the Go Playground):

Expecting true: true
Expecting false: false
Expecting true: true

Another option would be to use reflect.Value.Pointer() to get the address of the function values, this is exactly what the fmt package does: fmt/print.go:

func (p *pp) fmtPointer(value reflect.Value, verb rune) {
    // ...
    case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice,
            reflect.UnsafePointer:
        u = value.Pointer()
    // ...
}

But you should refactor and not compare function value addresses.

答案2

得分: 8

没问题,以下是翻译好的内容:

不用担心,找到答案了:

runtime.FuncForPC(reflect.ValueOf(handler.Post).Pointer()).Name() != 
   runtime.FuncForPC(reflect.ValueOf(Undefined).Pointer()).Name()
英文:

Nevermind, found the answer:

runtime.FuncForPC(reflect.ValueOf(handler.Post).Pointer()).Name() != 
   runtime.FuncForPC(reflect.ValueOf(Undefined).Pointer()).Name()

答案3

得分: 0

你不能直接比较函数。需要将函数存储到一个变量中,并将其作为指针引用。

http://play.golang.org/p/sflsjjCHN5

英文:

You can't compare function. It need to be stored into a variable instead and reference it as pointer.

http://play.golang.org/p/sflsjjCHN5

huangapple
  • 本文由 发表于 2016年1月20日 21:24:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/34901307.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定