我有这些模型:
trait Vehicle[T <: Vehicle[T]] { def update(): T }
class Car extends Vehicle[Car] { def update() = new Car() }
class Bus extends Vehicle[Bus] { def update() = new Bus() }
如果我获得
Vehicle[Car]
的实例并调用 update()
,我会得到一个Car
.由于Car
扩展 Vehicle[Car]
(或者简单地说,Car 是 Vehicle[Car]),我可以安全地将结果的类型显式设置为 Vehicle[Car]
:val car = new Car
val anotherCar = car.update()
val anotherCarAsVehicle: Vehicle[Car] = car.update() // works as expected
但是如果我想,比如说,放置
Car
的实例和 Bus
一起成为一个列表,然后我必须将列表类型设置为Vehicle[_ <: Vehicle[_]]
(有一个简单的列表 Vehicle[_]
并在一个元素上调用 update()
将产生 Any
,但我希望能够使用 update()
所以我必须使用 F 有界类型)。使用存在类型会破坏类型关系,因为一旦我从 Vehicle 中获取底层汽车/公共(public)汽车,我就不能再将其转换为 Vehicle 因为......好吧,它只是一些存在类型:val seq = List[Vehicle[_ <: Vehicle[_]]](new Car, new Bus)
val car = seq.head.update()
val carAsVehicle: Vehicle[_ <: Vehicle[_]] = seq.head.update() // fails to compile
所以,
Vehicle
用某种类型参数化 T
它是 Vehicle[T]
的子类型.当我撕掉 T
(通过使用 update()
),在具体类型的情况下没关系 - 例如如果我撕掉 Car
,我可以肯定地说我撕掉了 Vehicle[Car]
因为Car <: Vehicle[Car]
.但是,如果我撕掉一个存在类型,我就无能为力了。前面的例子有效,因为 Car
是 Vehicle[Car]
, 但在这种情况下 _
不是 Vehicle[_]
.指定 我的具体问题 : 对于上面给出的模型(车辆、汽车、公共(public)汽车),有没有办法实现这一点?
def sameType[T, U](a: T, b: U)(implicit evidence: T =:= U) = true
val seq = List[Vehicle[_ <: Vehicle[_]]](new Car, new Bus)
sameType(seq.head.update +: seq.tail, seq) // true
请注意,您可以更改
seq
的给定特征、类和类型。 ,但有一个限制:update()
必须返回 T
,而不是 Vehicle[T]
.我知道使用无形
HList
将解决问题,因为我不必使用存在类型(我只需有一个汽车和公共(public)汽车的列表,并且该类型信息将被保留)。但我想知道这个特殊的用例有一个简单的 List
.编辑 :
@RomKazanova 是的,那当然可以,但是我需要在
update()
之前和之后保留相同的类型(不过,这是对这项努力的支持;))。我相信没有 HList 或类似的数据结构是不可能的,因为统一汽车和公共(public)汽车迫使我们使用车辆类型,这会丢失关于其基础类型是 Car、Bus 还是其他东西的信息(我们所知道的是它是一些输入
_ <: Vehicle
)。但我想和你们核实一下。
最佳答案
我对存在类型不是很好,所以我不能解释太多:-p 但是当你改变 seq
的类型时至List[Vehicle[T] forSome {type T <: Vehicle[T]}]
一切似乎都“解决了”。请注意,您必须将类型传递给 List
构造函数/应用方法。
scala> val seq = List[Vehicle[T] forSome {type T <: Vehicle[T]}](new Car, new Bus)
seq: List[Vehicle[T] forSome { type T <: Vehicle[T] }] = List(Car@31e53802, Bus@54d569e7)
scala> sameType(seq.head.update +: seq.tail, seq)
res3: Boolean = true
scala> seq.head.update
res4: T forSome { type T <: Vehicle[T] } = Car@79875bd2
scala> seq.head.update.update
res5: T forSome { type T <: Vehicle[T] } = Car@6928c6a0
scala> new Car +: seq
res6: List[Vehicle[T] forSome { type T <: Vehicle[T] }] = List(Car@51f0a09b, Car@31e53802, Bus@54d569e7)
我认为摆脱这个答案的主要问题是,这可以让您阐明
Vehicle
的递归性质。类型构造函数。我不确定我会推荐这个虽然......
关于scala - 解析 F 有界多态性中的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42436336/