在Go中使用空接口返回类型接受参数中的函数

时间:2015-09-02 06:09:57

标签: go

我是Go的新手,我想了解为什么下面的代码段无法编译。将函数作为可能具有任何返回类型的函数参数接受的Go方式是什么?

package main

func main() {
    test(a) // Error: cannot use a (type func() string) as type func() interface {} in argument to test
    test(b) // Error: cannot use b (type func() int) as type func() interface {} in argument to test
}

func a() string {
    return "hello"
}

func b() int {
    return 1
}

func test(x func() interface{}) {

    // some code...
    v := x()
    // some more code....
}

播放:https://play.golang.org/p/CqbuEZGy12

我的解决方案基于Volker的回答:

package main

import (
    "fmt"
)

func main() {

    // Wrap function a and b with an anonymous function
    // that has an empty interface return type. With this
    // anonymous function, the call signature of test
    // can be satisfied without needing to modify the return
    // type of function a and b.

    test(func() interface{} {
        return a()
    })

    test(func() interface{} {
        return b()
    })
}

func a() string {
     return "hello"
}

func b() int {
    return 1
}

func test(x func() interface{}) {
    v := x()
    fmt.Println(v)  
}

播放:https://play.golang.org/p/waOGBZZwN7

2 个答案:

答案 0 :(得分:11)

你为Go新手绊倒了一个非常常见的误解:空接口interface{} 意味着“任何类型”。真的,它没有。 Go是静态类型的。空接口interface {}是实际的(强类型类型),例如stringstruct{Foo int}interface{Explode() bool}

这意味着如果某个类型interface{}具有该类型而不是“任何类型”。

你的功能

func test(x func() interface{})

需要一个参数。此参数是(无参数函数),它返回特定类型,类型interface{}。您可以将任何函数传递给符合此签名的test:“无参数并返回interface{}”。您的所有功能ab都不符合此签名。

如上所述:interface {}不是“what”的神奇缩写,它是一种独特的静态类型。

你必须改变,例如a至:

func a() interface{} {
    return "hello"
}

现在,当您返回不属于string类型的interface{}时,这可能会显得很奇怪。这是有效的,因为任何类型都可以赋值给interface{}类型的变量(因为每种类型都至少没有方法:-)。

答案 1 :(得分:2)

正如Go specification所述:

  

函数类型表示具有相同参数的所有函数的集合,结果类型

在您的情况下,结果类型不同(string vs interface{}

为了能够接收任何类型的结果类型的函数,test必须定义为:

func text(x interface{}) { ... }

然后您必须使用reflect package来调用x中存储的函数。

修改

这样的test函数看起来像这样:

func test(x interface{}) {
    v := reflect.ValueOf(x)

    if v.Kind() != reflect.Func {
        panic("Test requires a function")
    }

    t := v.Type()

    if t.NumIn() != 0 && t.NumOut() != 1 {
        panic("Function type must have no input parameters and a single return value")
    }

    values := v.Call(nil)

    val := values[0].Interface()
    // some more code..
}

游乐场: https://play.golang.org/p/trC2lOSLNE