Scala:为什么不编译?

时间:2012-10-18 18:35:58

标签: scala generics

假设:

class Foo[T] {
 def get: T
}

class Bar
class FooBar extends Foo[Bar] {
 def get = new Bar
}

object Baz {
    def something [T, U <: Foo[T]] (foo : Class[U]): T = foo.newInstance.get
}

我应该可以做这样的事情,对吧?

Baz.something(classOf[FooBar])

奇怪的是这是在扔:

inferred type arguments [Nothing,this.FooBar] do not conform to method something's type parameter bounds [T,U <: this.Foo[T]]

这很奇怪:S。顺便说一句我在迁移一些与我在这里写的东西相当的java代码时遇到了这个问题,而且工作正常。

3 个答案:

答案 0 :(得分:6)

你遇到了Scala类型推断的一个更烦人的限制!请参阅this answer,以清楚地解释编译器在这里窒息的原因。

你有一些选择。最简单的是你可以自己提供类型:

Baz.something[Bar, FooBar](classOf[FooBar])

但那令人讨厌的冗长。如果你真的不关心U,你可以将它从类型参数列表中删除:

object Baz {
  def something[T](foo: Class[_ <: Foo[T]]): T = foo.newInstance.get
}

现在FooBar将在您的示例中正确推断。您还可以使用上面链接的答案中讨论的技巧:

object Baz {
  def something[T, U <% Foo[T]](foo: Class[U]): T = foo.newInstance.get
}

为什么这个工作有点棘手 - 关键是在视图绑定被去除后,T不再出现在U的界限中。

答案 1 :(得分:5)

它没有编译,因为T没有出现在参数列表的任何地方,因此无法推断(或者更确切地说,推断为Nothing)。

你可以这样解决:

def something [T] (foo : Class[_ <: Foo[T]]): T = foo.newInstance.get

答案 2 :(得分:0)

明确添加类型似乎有效:

scala> Baz.something[Bar,FooBar](classOf[FooBar])
res1: Bar = Bar@3bb0ff0

通常,当你得到一个Nothing,你期望推断出其他类型时,意味着由于某种原因,编译器无法推断出该特定位置的类型。

那就是说,我提出了一个问题:我们如何重构代码以便推断出类型? @Régis的回答显示了解决方案。