我无法理解为什么,如果我指定我的函数scala编译器的返回类型抱怨。我很确定它正在发生,因为我正在使用F-bounded polymorphism。 scala(2.11)shell上的所有内容。这是我的班级定义:
trait Base[T <: Base[T]]
case class Derived(id: Long) extends Base[Derived]
这可行(没有显式返回类型):
def buildThisWorks1[T<:Base[T]]() = Derived(1)
然而,这不起作用:
def buildNotWorking[T<:Base[T]]() : T = Derived(1)
<console>:10: error: type mismatch;
found : Derived
required: T
def buildNotWorking[T<:Base[T]]() : T = Derived(1)
如果我将Derived
类强制转换为类型T
,那么它会起作用,这让我感到困惑。
def buildThisWorks2[T<:Base[T]]() : T = Derived(1).asInstanceOf[T]
请注意,在第二个定义中,我将Derived
作为T
的实例(根据我的说法,这是多余的,因为Derived已经是Base
的子类型,但它有效。)
def buildThisWorks2[T<:Base[T]]() : T = Derived(1).asInstanceOf[T]
答案 0 :(得分:2)
如果未指定此方法的返回类型,编译器会推断出它:
scala> def buildThisWorks1[T <: Base[T]]() = Derived(1)
buildThisWorks1: [T <: Base[T]]()Derived
此处,返回类型推断为Derived
,而不是T
。实际上,type参数在这里绝对没有任何意义,因为该方法将始终返回Derived
类型。
以下内容无效,因为我们不知道T = Derived
。 T
可以是满足约束T <: Derived[T]
的任何类型。虽然这里只有一种类型满足条件,但编译器不会假设T = Derived
。您可以轻松添加class Extra extends Base[Extra]
,这会突然而神秘地导致方法中断(如果它首先起作用)。
def buildNotWorking[T <: Base[T]]() : T = Derived(1)
类型转换有效,因为您强制Derived(1)
的类型为T
的类型。如果T
实际上是Derived
,那么一切都还可以。
def buildThisWorks2[T <: Base[T]]() : T = Derived(1).asInstanceOf[T]
但是演员告诉编译器忽略任何类型错误,这会在运行时引起问题。如果T
不是Derived
,那么您将遇到问题。
class Bad extends Base[Bad]
scala> buildThisWorks2[Bad]
java.lang.ClassCastException: Derived cannot be cast to Bad
... 33 elided
我们得到ClassCastException
,因为T
实际上是Bad
类型,Derived
无法投放到其中。
总而言之,目前还不清楚你想要做什么。通常,类型参数是从方法的参数推断出来的。但是这里没有这个方法的参数,所以没有什么可以推断参数类型。编译器对此没问题,因为您仍然可以手动提供类型参数(正如我在导致异常的示例中所做的那样)。无法从方法的返回值推断出类型参数T
,因为它通常应该依赖于调用者通过参数(或者是静态的)。
基本上,这些方法的类型参数不起作用,并且完全被忽略,因为每次都返回相同的类型Derived
。更有意义的东西会接受Base[T]
作为参数,用它做一些事情,并返回它(也许?)。
def doSomething[T <: Base[T]](t: T): T = t // not very creative