【问题标题】:Accept function in argument with empty interface return type接受具有空接口返回类型的参数中的函数
【发布时间】:2015-09-02 06:09:57
【问题描述】:

我想了解为什么下面的代码 sn-p 无法编译。 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

【问题讨论】:

    标签: go


    【解决方案1】:

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

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

    你的功能

    func test(x func() interface{})
    

    采用一个参数。这个参数是一个(无参数函数),它返回一个特定的类型,类型interface{}。您可以将任何与此签名匹配的函数传递给test:“无参数并返回interface{}”。您的函数 ab 都不匹配此签名。

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

    你必须改变例如一个到:

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

    现在这可能看起来很奇怪,因为您返回的string 不是interface{} 类型。这是可行的,因为任何类型都可以分配给interface{} 类型的变量(因为每种类型至少没有方法:-)。

    【讨论】:

    • 我更同意你的解决方案:)。如果可能,最好避免反射。
    • 这就像按任意键和按“任意”键的区别。
    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      相关资源
      最近更新 更多