请考虑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])作用同样合适......不需要暗示等等.
它并没有真正回答"为什么"部分,对不起,但这里有一些你可以玩的技巧.首先,因为你没有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实例化,就像你一直都知道的那样.
编译器无法自动推断A. 但如果有可能,它必须说A应该是Int 的超类型,所以Int或Any,而不仅仅是Int!.因为List [Int] <:List [Any].因此,如果编译器会推断Int为A,那么限制性太强.
换一种说法:
case class Foo[A, B <: List[A]](l: B) { ... }
然后调用它,因为Foo(List(1,2,3))你说A必须是一个类型,其中包含它的列表应该是Int列表的超类型.所以有效A必须是Int的超类型,因为List是协变的.
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)你将无法做到这一点.
所以这两个案例并不相同.
| 归档时间: |
|
| 查看次数: |
259 次 |
| 最近记录: |