基本型推断

时间:2012-01-05 19:56:25

标签: scala types

请考虑case class Foo[A, B <: List[A]](l: B) { ... }或类似的事情。特别是A以及B需要在Foo的正文中提供。

编译器是否可以自动推断A?例如,Foo(List(1,2,3))失败,因为类型检查器会将A推断为Nothing。也许有一种方法可以使用类型成员来解决这个问题?

我有一种感觉,我在这里忽略了一些非常简单的东西;)

编辑:我刚刚发现使用其他类型参数X的工作正常,但是我不明白为什么会这样:

scala> case class Bar[A, B[X] <: List[X]](l: B[A])
defined class Bar

scala> Bar(List(1,2,3))
res11: Bar[Int,List] = Bar(List(1, 2, 3))

有人可以向我解释一下吗? 这是一个统一问题吗?

编辑2:使用[A, B[X] <: List[X]](l: B[A])会对某些层次结构产生不良影响(尽管这并不是什么大问题)。更有趣的是,我偶然发现了Josh Suereth的blog post,隐含地表明[A, B <: List[A]](l: B with List[A])同样有效......不需要暗示等等。

3 个答案:

答案 0 :(得分:5)

它并没有真正回答“为什么”部分,对不起,但这里有一些你可以玩的技巧。首先,由于您未在示例中使用X,因此可以写:

case class Bar[A,B[_] <: Seq[_]](l : B[A])

然后:

scala> Bar(List(1,2,3))
resN: Bar[Int,List] = Bar(List(1, 2, 3))

(我使用协变Seq代替List来表明它也适用于子类型。另请注意,这不等于使用额外的X,请参阅评论。)不幸的是,每次你想要使用序列类型时,你需要编写B[A],即手动实例化它。解决这个问题的一种方法是改为编写:

case class Bar[A,B](l : B)(implicit ev : B <:< Seq[A])

行动中:

scala> Bar(List(1,2,3))
resN: Bar[Int,List[Int]] = Bar(List(1, 2, 3))

...你得到的类型参数AB实例化就像你一直都知道的那样。

答案 1 :(得分:5)

编译器无法自动推断A.但是,如果有可能,则必须说A应该是Int的超类型,所以Int或Any,而不仅仅是Int!。因为List [Int]&lt ;: List [Any]。因此,如果编译器会推断Int为A,那么限制性太强。

换句话说:

  1. case class Foo[A, B <: List[A]](l: B) { ... } 然后将其称为Foo(List(1,2,3)),你说 A必须是一个类型,其中包含它的列表应该是Int 列表的超类型。 所以有效A必须是Int的超类型,因为List是协变的。

  2. case class Bar[A, B[X] <: List[X]](l: B[A]) 然后将其称为Foo(List(1,2,3)),您说 A必须是Int

  3. 案例(2)没有留下任何除了Int之外的空间。 然而,情况(1)为A留下了除Int以外的空间,例如它可能是任何。 你可以看到这个,因为你可以通过Foo[Any, List[Int]](List(1,2,3))来调用它。在案例(2)中你将无法做到这一点。

    所以这两个案例并不相同。

答案 2 :(得分:2)

根据Alexey Romanov,原则上可以自动推断出类型,但目前还不是。

因此,至少目前,所有应推断的类型参数都必须在参数中明确显示。