请考虑 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))
有人可以向我解释一下吗? 这是一个统一问题吗?
编辑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])
接着:
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))
...而且你得到了类型参数 A
和 B
就像你一直都知道的那样实例化。
编译器无法自动推断A.但如果有可能,就必须说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以外的空间,例如它可能是任何。
你可以看到这个,因为你可以通过它来调用它 Foo[Any, List[Int]](List(1,2,3))
。在案例(2)中你将无法做到这一点。
所以这两个案例并不相同。
根据 阿列克谢罗曼诺夫原则上,类型可以自动推断,但目前还不是。
因此,至少目前,应该推断的所有类型参数都必须在参数中显式显示。