基本型推断

fot*_*ton 11 types scala

请考虑case class Foo[A, B <: List[A]](l: B) { ... }或类似的东西.特别是,A还B需要在身体的某个地方可用Foo.

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

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

编辑:我刚刚发现使用另一个类型参数X工作得很好,但atm我不明白为什么会这样:

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))
Run Code Online (Sandbox Code Playgroud)

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

编辑2:使用[A, B[X] <: List[X]](l: B[A])可能会对某些层次结构产生不良影响(尽管这并不是什么大问题).更有趣的是,我偶然发现了Josh Suereth撰写的一篇博文,其中隐含地表明它的[A, B <: List[A]](l: B with List[A])作用同样合适......不需要暗示等等.

Phi*_*ppe 5

它并没有真正回答"为什么"部分,对不起,但这里有一些你可以玩的技巧.首先,因为你没有X在你的例子中使用,你可以写:

case class Bar[A,B[_] <: Seq[_]](l : B[A])
Run Code Online (Sandbox Code Playgroud)

然后:

scala> Bar(List(1,2,3))
resN: Bar[Int,List] = Bar(List(1, 2, 3))
Run Code Online (Sandbox Code Playgroud)

(我正在使用协变Seq而不是List显示它适用于子类型.另外,请注意,这不等于使用额外的X,请参阅注释.)不幸的是,每次要使用序列类型时,您需要写B[A],即手动实例化.解决这个问题的一种方法是改为:

case class Bar[A,B](l : B)(implicit ev : B <:< Seq[A])
Run Code Online (Sandbox Code Playgroud)

在行动:

scala> Bar(List(1,2,3))
resN: Bar[Int,List[Int]] = Bar(List(1, 2, 3))
Run Code Online (Sandbox Code Playgroud)

...你得到了类型参数A并B实例化,就像你一直都知道的那样.


Jan*_*rst 5

编译器无法自动推断A. 但如果有可能,它必须说A应该是Int 的超类型,所以Int或Any,而不仅仅是Int!.因为List [Int] <: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.

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

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


fot*_*ton 2

根据Alexey Romanov 的说法,原则上可以自动推断类型,但目前还不能自动推断。

因此,至少现在,所有应该推断的类型参数都必须显式地显示在参数中。