将函数赋值给变量时,为什么编译器需要完美的函数签名匹配...
将这个例子放在......
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
值有什么不同?答案 0 :(得分:3)
简而言之,Fooer不是FooerBarer。两者都是接口类型,但它们指向不同的itables。保证Fooer的第一种方法是Foo() Fooer
。在FooerBarer中,它可能有Bar() FooerBarer
作为其第一种方法。因此,在运行时,方法查找将返回错误的方法。
保证从FooerBarer到Fooer的任何转换都会成功,因为FooerBarer始终具有Fooer所需的方法集。接口转换的工作方式,运行时首先查找它收到的FooerBarer的实际类型(例如条形图),然后查找bar / Fooer对的itable并创建一个新的接口值。
在Go代码中,您可以明确或隐式地使其发生。例如x := Fooer(myFooerBarer)
。这将进行显式转换并将新接口值放在x中。如果您具有类型func(Fooer)
的函数并传递了FooerBarer,则转换将隐式发生。编译器将执行转换并将结果分配给函数调用的参数。
在上述情况下,您正尝试将func() FooerBarer
分配给func() Fooer
。在Go中,没有赋值具有自动转换。您不能将double赋给int。即使它们的基础类型相同,您甚至无法将time.Duration分配给int64。在这种情况下,需要对函数进行换行,以便每次运行函数时都可以进行转换。不允许同一基础类型之间的转换是自动的,并且自动包装函数会有点不一致。
如果你真的需要做这样的事情,那么答案很简单。只需包装该功能。
var fbmake = func() FooerBarer {
return &bar{}
}
var fmake Fmaker = func() Fooer {
return fbmake()
}