Scala方法无法推断返回类型

时间:2015-04-29 02:21:18

标签: scala

我无法理解为什么,如果我指定我的函数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]

1 个答案:

答案 0 :(得分:2)

如果未指定此方法的返回类型,编译器会推断出它:

scala> def buildThisWorks1[T <: Base[T]]() = Derived(1)
buildThisWorks1: [T <: Base[T]]()Derived

此处,返回类型推断为Derived,而不是T。实际上,type参数在这里绝对没有任何意义,因为该方法将始终返回Derived类型。

以下内容无效,因为我们不知道T = DerivedT可以是满足约束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