我一直在努力学习更多Scala并遇到this interesting article讨论F-bounded类型。关于使用这些类型的值集合进行最后讨论,我特别感兴趣。
一个简单的例子如下:
abstract class AbsClass[A <: AbsClass[_]] {
this: A =>
def me: A = this
}
def me2[A <: AbsClass[A]](a: A): A = a
case class C1(v: Int) extends AbsClass[C1]
case class C2(v: Int) extends AbsClass[C2]
如博文中所示,我们可以使用存在量词来允许我们在me2
和C1
C2
scala> List[A forSome {type A <: AbsClass[A] }](C1(1), C2(2)).map(me2(_))
res2: List[A forSome { type A <: AbsClass[A] }] = List(C1(1), C2(2))
现在,我一直在尝试列表类型的几种变体, 我希望有更多经验的人可能会指出一些微妙之处 我失踪了。
以下工作正如我所预料的那样
scala> val l2 = List[A forSome {type A <: AbsClass[A] }](C1(1), C2(2))
l2: List[A forSome { type A <: AbsClass[A] }] = List(C1(1), C2(2))
scala> l2.map(_.me)
res4: List[A forSome { type A <: AbsClass[A] }] = List(C1(1), C2(2))
我也可以致电_.me
并将该列表表示为包含AbsClass[A] forSome {type A}
的实例,如
scala> val l: List[AbsClass[_]] = List(C1(1), C2(2)).map(_.me)
l: List[AbsClass[_]] = List(C1(1), C2(2))
但是当我尝试再次将相同的地图应用于l
时,我会丢失类型信息
我被List[Any]
困住了。有没有办法在这里维护类型?
答案 0 :(得分:1)
请记住,下划线是一种类型绑定。
val l: List[AbsClass[_]] = List(C1(1), C2(2)).map(_.me)
val ll: List[AbsClass[_ >: Nothing <: Any]] = List(C1(1), C2(2)).map(_.me)
这两件事是一样的。下划线将压缩到Nothing的下限或Any的上限。
有关存在类型如何工作的详细信息,请参阅:https://youtu.be/NFnsFda82Yo