-2

将函数分配给变量时,为什么编译器需要完美的函数签名匹配...

  • 变量的类型是一个函数,其参数或返回是一个特定的接口,并且
  • 被分配的功能需要不同的接口,但是是嵌入了预期接口的接口。

举这个例子,其中......

  • 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{}
}

所以我的问题不是关于替代解决方案,而是为什么编译器是以这种方式构建的。

似乎编译器会看到通过返回 a FooerBarer,因此您正在返回 a Fooer,并且会接受分配。

所以...

  • 编译器这种严格行为的原因是什么?
  • 正在解决什么问题或正在避免什么危险?
  • 为什么这与编译器接受FooerBarer赋值给Fooer变量的值有什么不同?
4

1 回答 1

3

简单地说,Fooer 不是 FooerBarer。两者都是接口类型,但它们指向不同的 itable。A Fooer 保证在 itable be 中具有第一个方法Foo() Fooer。在 FooerBarer 中,它可能有Bar() FooerBarer它的第一个方法。所以在运行时,方法查找会返回错误的方法。

从 FooerBarer 到 Fooer 的任何转换都保证成功,因为 FooerBarer 始终具有 Fooer 所需的方法集。接口转换的工作方式是,运行时首先查找它收到的 FooerBarer 的真实类型(例如 bar),然后查找 bar/Fooer 对的 itable 并创建一个新的接口值。

在 Go 代码中,您可以显式或隐式地导致这种情况发生。例如x := Fooer(myFooerBarer). 这将进行显式转换并将新的接口值放在 x 中。如果你有一个类型的函数func(Fooer)并传递了一个 FooerBarer,那么转换就会隐式发生。编译器将进行转换并将结果分配给函数调用的参数。

在上述情况下,您正试图将 a 分配func() FooerBarer给 a func() Fooer。在 Go 中,没有分配具有自动转换。您不能将 double 分配给 int。即使它们的基础类型相同,您甚至不能将 time.Duration 分配给 int64。在这种情况下,需要包装函数,以便每次运行函数时都可以完成转换。不允许相同底层类型之间的自动转换和自动包装函数会有点不一致。

如果你真的需要做这样的事情,有一个简单的答案。只需包装函数。

var fbmake = func() FooerBarer {
    return &bar{}
}

var fmake Fmaker = func() Fooer {
    return fbmake()
}
于 2012-10-27T23:35:30.103 回答