将函数分配给变量时,为什么编译器在以下情况下需要完美的函数签名匹配...
以这个例子为例...
Fooer
是一个接口FooerBarer
是嵌入Fooer
接口*bar
实现FooerBarer
http://play.golang.org/p/8NyTipiQak
// Define a type that is a function that returns a Fooer interface
type FMaker func() Fooer
/* Define values of the FMaker type */
// This works, because the signature matches the FMaker type
var fmake FMaker = func() Fooer {
return &bar{}
}
// This causes an error even though a FooerBarer is a Fooer
var fmake2 FMaker = func() FooerBarer {
return &bar{}
}
所以我的问题不是关于替代解决方案,而是为什么编译器是以这种方式构建的。
似乎编译器将看到通过返回
FooerBarer
,因此您正在返回Fooer
,并且将接受分配。所以...
FooerBarer
变量时接受Fooer
值有什么不同? 最佳答案
简单地说,Fooer不是FooerBarer。两者都是接口类型,但是它们指向不同的itable。确保Fooer在itable中具有第一个方法是Foo() Fooer
。在FooerBarer中,它的第一个方法可能是Bar() FooerBarer
。因此,在运行时,方法查找将返回错误的方法。
从FooerBarer到Fooer的任何转换都可以确保成功,因为FooerBarer始终具有Fooer所需的方法集。接口转换的工作方式是,运行时首先查找它收到的FooerBarer的真实类型(例如条形),然后查找条/ Fooer对的可访问类型并创建一个新的接口值。
在Go代码中,您可以使这种情况显式或隐式地发生。例如x := Fooer(myFooerBarer)
。这将进行显式转换并将新的接口值放在x中。如果您具有func(Fooer)
类型的函数并传递了FooerBarer,则转换将隐式发生。编译器将进行转换并将结果分配给函数调用的参数。
在上述情况下,您尝试将func() FooerBarer
分配给func() Fooer
。在Go中,没有分配具有自动转换。您不能将double分配给int。即使它们的基础类型相同,您甚至无法为int64分配time.Duration。在这种情况下,将需要包装函数,以便每次运行该函数时都可以完成转换。不允许同一基础类型之间的转换是自动的,并且自动包装函数之间的转换会有点不一致。
如果您确实需要执行以下操作,则有一个简单的答案。只需包装功能。
var fbmake = func() FooerBarer {
return &bar{}
}
var fmake Fmaker = func() Fooer {
return fbmake()
}