函数类型中的Golang空接口{}

Yiq*_* Hu 12 interface function go

可以将任何类型的对象分配给空接口.例如,我们有以下功能

func Println(i interface{} ) {
  fmt.Println(i)
}
Run Code Online (Sandbox Code Playgroud)

我们可以称之为

Println(3)
Println(1.5)
Println("Hello")
Run Code Online (Sandbox Code Playgroud)

但是我无法为功能类型实现同样的功能

func Map(fn func( interface{} )) {  
  ......  
}  
Run Code Online (Sandbox Code Playgroud)

我无法调用它,
Map( func( i int) {......} )
因为类型与类型func(int)不同func( interface{} ).

但是当我定义时func( interface{} ),我的意思是任何类型的输入参数.我怎样才能在Golang中实现这一目标?

Jam*_*dge 13

它失败,因为签名不匹配.

当您调用时Println(3),该函数不会将整数作为其第一个参数.而是整数被包装在interface{}变量中(自动转换,因为整数符合接口),并且该变量被传递给函数.这种转换发生在主叫端,因此调用该函数的过程与调用函数匹配不同func(i int).

如果要编写一个接受任意一元函数的函数,则需要声明它将interface{}变量作为参数,然后使用该reflect包检查该值.该reflect包还可以帮助您在编译时调用不知道签名的任意函数.

例如:

func Map(f, v interface{}) interface{} {
    fn := reflect.ValueOf(f)
    fnType := fn.Type()
    if fnType.Kind() != reflect.Func || fnType.NumIn() != 1 || fnType.NumOut() != 1 {
        panic("Expected a unary function returning a single value")
    }
    res := fn.Call([]reflect.Value{reflect.ValueOf(v)})
    return res[0].Interface()
}
Run Code Online (Sandbox Code Playgroud)

这将f使用参数调用给定函数v并返回结果.如果v可以分配给f第一个参数,则呼叫将成功而不会出现恐慌.您可以在此处试验此示例:http://play.golang.org/p/kkBu56JYb8