英文:
Accept function in argument with empty interface return type
问题
我想了解一下下面的代码片段为什么无法编译。在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....
}
我的解决方案基于Volker的答案:
package main
import (
"fmt"
)
func main() {
// 使用匿名函数将函数a和b包装起来,匿名函数的返回类型为空接口。
// 通过这个匿名函数,可以满足test函数的调用签名,而无需修改函数a和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)
}
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?
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....
}
Play: https://play.golang.org/p/CqbuEZGy12
My solution based on Volker's answer:
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)
}
答案1
得分: 24
你被一个对于Go语言新手来说非常常见的误解所困扰:空接口interface{}
并不意味着"任意类型"。实际上,它并不是这样的。Go是静态类型语言。空接口interface{}
是一个实际的(强类型)类型,就像string
、struct{Foo int}
或interface{Explode() bool}
一样。
这意味着如果某个东西的类型是interface{}
,它就是这个类型,而不是"任意类型"。
你的函数
func test(x func() interface{})
接受一个参数。这个参数是一个无参数函数,它返回一个特定的类型,即interface{}
类型。你可以传递任何符合这个签名的函数给test
函数:"没有参数并返回interface{}
"。你的函数a
和b
都不符合这个签名。
如上所述:interface{}
并不是一个"任意类型"的神奇缩写,它是一个独立的静态类型。
你需要修改函数a
,例如:
func a() interface{} {
return "hello"
}
现在这看起来可能有些奇怪,因为你返回的是一个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
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:
func a() interface{} {
return "hello"
}
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规范所述:
函数类型表示具有相同参数和结果类型的所有函数的集合
在你的情况下,你的结果类型是不同的(string
与interface{}
)。
为了能够接收任何类型的结果类型的函数,test
必须被定义为:
func test(x interface{}) { ... }
然后,你将需要使用reflect包来调用存储在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()
// 一些其他代码..
}
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:
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:
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..
}
Playground: https://play.golang.org/p/trC2lOSLNE
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论