如何比较 Go 中的 2 个函数?

问题描述 投票:0回答:4

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

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

如果两个函数相同,正确的比较方法是什么?

function pointers go function-pointers
4个回答
20
投票

在进一步讨论之前:您应该重构而不是比较函数值地址。

规范:比较运算符:

切片、贴图和函数值不具有可比性。然而,作为特殊情况,切片、映射或函数值可以与预先声明的标识符

nil
进行比较。

功能值不具有可比性。您可以做的是比较函数值的地址是否相同(不是保存函数值的变量的地址,而是函数值本身)。

您无法获取函数的地址,但如果您使用

fmt
包打印它,它会打印它的地址。所以你可以使用
fmt.Sprintf()
来获取函数值的地址。

请参阅此示例(基于您的代码):

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

输出(在Go Playground上尝试一下):

Expecting true: true
Expecting false: false
Expecting 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()
    // ...
}

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


8
投票

没关系,找到答案了:

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

0
投票

你无法比较功能。它需要存储到一个变量中并将其作为指针引用。

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


0
投票

有充分的理由不比较函数。如果函数本身没有唯一的标识,我们就不需要为它们分配内存。此外,编译器可能会选择内联您的函数,使同一函数具有多个地址或根本没有可调用地址。该规范禁止通过函数比较来优化您的代码。这是一件好事,你应该拥抱它。

© www.soinside.com 2019 - 2024. All rights reserved.