接受一个参数为空接口类型的函数,并返回空接口类型。

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

Accept function in argument with empty interface return type

问题

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

  1. package main
  2. func main() {
  3. test(a) // Error: cannot use a (type func() string) as type func() interface {} in argument to test
  4. test(b) // Error: cannot use b (type func() int) as type func() interface {} in argument to test
  5. }
  6. func a() string {
  7. return "hello"
  8. }
  9. func b() int {
  10. return 1
  11. }
  12. func test(x func() interface{}) {
  13. // some code...
  14. v := x()
  15. // some more code....
  16. }

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. // 使用匿名函数将函数a和b包装起来,匿名函数的返回类型为空接口。
  7. // 通过这个匿名函数,可以满足test函数的调用签名,而无需修改函数a和b的返回类型。
  8. test(func() interface{} {
  9. return a()
  10. })
  11. test(func() interface{} {
  12. return b()
  13. })
  14. }
  15. func a() string {
  16. return "hello"
  17. }
  18. func b() int {
  19. return 1
  20. }
  21. func test(x func() interface{}) {
  22. v := x()
  23. fmt.Println(v)
  24. }

Play链接:https://play.golang.org/p/waOGBZZwN7

英文:

I would like to understand why the code snippet below does not compile. What is the Go way of accepting a function as a function argument that may have any return type?

  1. package main
  2. func main() {
  3. test(a) // Error: cannot use a (type func() string) as type func() interface {} in argument to test
  4. test(b) // Error: cannot use b (type func() int) as type func() interface {} in argument to test
  5. }
  6. func a() string {
  7. return "hello"
  8. }
  9. func b() int {
  10. return 1
  11. }
  12. func test(x func() interface{}) {
  13. // some code...
  14. v := x()
  15. // some more code....
  16. }

Play: https://play.golang.org/p/CqbuEZGy12

My solution based on Volker's answer:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. // Wrap function a and b with an anonymous function
  7. // that has an empty interface return type. With this
  8. // anonymous function, the call signature of test
  9. // can be satisfied without needing to modify the return
  10. // type of function a and b.
  11. test(func() interface{} {
  12. return a()
  13. })
  14. test(func() interface{} {
  15. return b()
  16. })
  17. }
  18. func a() string {
  19. return "hello"
  20. }
  21. func b() int {
  22. return 1
  23. }
  24. func test(x func() interface{}) {
  25. v := x()
  26. fmt.Println(v)
  27. }

Play: https://play.golang.org/p/waOGBZZwN7

答案1

得分: 24

你被一个对于Go语言新手来说非常常见的误解所困扰:空接口interface{}并不意味着"任意类型"。实际上,它并不是这样的。Go是静态类型语言。空接口interface{}是一个实际的(强类型)类型,就像stringstruct{Foo int}interface{Explode() bool}一样。

这意味着如果某个东西的类型是interface{},它就是这个类型,而不是"任意类型"。

你的函数

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

接受一个参数。这个参数是一个无参数函数,它返回一个特定的类型,即interface{}类型。你可以传递任何符合这个签名的函数给test函数:"没有参数并返回interface{}"。你的函数ab都不符合这个签名。

如上所述:interface{}并不是一个"任意类型"的神奇缩写,它是一个独立的静态类型。

你需要修改函数a,例如:

  1. func a() interface{} {
  2. return "hello"
  3. }

现在这看起来可能有些奇怪,因为你返回的是一个string类型,而不是interface{}类型。但这是可以工作的,因为任何类型都可以赋值给interface{}类型的变量(因为每个类型至少没有方法 :-))。

英文:

You tripped over a very common misconception for Go newcomers: The empty interface interface{} does not mean "any type". Really, it does not. Go is statically typed. The empty interface interface {} is an actual (strongly typed type) like e.g. string or struct{Foo int} or interface{Explode() bool}.

That means if something has the type interface{} it has that type and not "any type".

Your function

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

takes one parameter. This parameter is a (parameterless function) which returns a specific type, the type interface{}. You can pass any function to test which matches this signature: "No parameters and return interface{}". None of your functions a and b match this signature.

As said above: interface {} is not a magical abbreviation for "whatever",it is a distinct static type.

You have to change e.g. a to:

  1. func a() interface{} {
  2. return "hello"
  3. }

Now this might look strange as you return a string which is not of type interface{}. This works because any type is assignable to variables of type interface{} (as every type has at least no methods :-).

答案2

得分: 3

根据Go规范所述:

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

在你的情况下,你的结果类型是不同的(stringinterface{})。

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

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

然后,你将需要使用reflect包来调用存储在x中的函数。

编辑

这样的test函数将如下所示:

  1. func test(x interface{}) {
  2. v := reflect.ValueOf(x)
  3. if v.Kind() != reflect.Func {
  4. panic("Test requires a function")
  5. }
  6. t := v.Type()
  7. if t.NumIn() != 0 && t.NumOut() != 1 {
  8. panic("Function type must have no input parameters and a single return value")
  9. }
  10. values := v.Call(nil)
  11. val := values[0].Interface()
  12. // 一些其他代码..
  13. }

Playground: https://play.golang.org/p/trC2lOSLNE

英文:

As the Go specification states:

> A function type denotes the set of all functions with the same parameter and result types

In your case, your result types differ (string vs interface{})

To be able to receive a function with any kind of result type, test would have to be defined as:

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

and then you will have to use reflect package to call the function stored in x.

Edit

Such a test function would look like this:

  1. func test(x interface{}) {
  2. v := reflect.ValueOf(x)
  3. if v.Kind() != reflect.Func {
  4. panic("Test requires a function")
  5. }
  6. t := v.Type()
  7. if t.NumIn() != 0 && t.NumOut() != 1 {
  8. panic("Function type must have no input parameters and a single return value")
  9. }
  10. values := v.Call(nil)
  11. val := values[0].Interface()
  12. // some more code..
  13. }

Playground: https://play.golang.org/p/trC2lOSLNE

huangapple
  • 本文由 发表于 2015年9月2日 14:09:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/32345760.html
匿名

发表评论

匿名网友

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

确定