slo*_*ouc 5 generics scala f-bounded-polymorphism
我有这些模型:
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() }
Run Code Online (Sandbox Code Playgroud)
如果我获得了一个a 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
Run Code Online (Sandbox Code Playgroud)
但是,如果我想,比如说,将实例Car和Bus一起放入一个列表中,那么我必须将列表类型设置为Vehicle[_ <: Vehicle[_]](具有简单的列表Vehicle[_]并且update()在元素上调用会产生Any,但我希望能够使用update()所以我必须使用F-bounded类型).使用存在类型搞定了类型关系,因为一旦我从Vehicle获取底层汽车/公共汽车,我就不能再将其投射到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
Run Code Online (Sandbox Code Playgroud)
因此,Vehicle使用某种类型参数化,T这是一种子类型Vehicle[T].当我撕掉T(通过使用update()),在具体类型的情况下它是好的 - 例如,如果我撕掉它Car,我可以安全地声称我撕掉了一个Vehicle[Car]因为Car <: Vehicle[Car].但如果我撕掉一个存在主义类型,我就无法做任何事情.早期的例子是因为Car是a Vehicle[Car],但在这种情况下_不是Vehicle[_].
指定我的具体问题:对于上面给出的模型(车辆,汽车,公共汽车),有没有办法实现这一目标?
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
Run Code Online (Sandbox Code Playgroud)
请注意,您可以更改给定的特征,类和类型seq,但有一个限制:update() 必须返回T,而不是Vehicle[T].
我知道使用无形HList将解决问题,因为我不必使用存在类型(我只需要一个汽车和公共汽车的列表,并且将保留该类型信息).但我想知道这个特殊用例的简单List.
编辑:
@RomKazanova是的,这当然会起作用,但我需要在之前和之后保留相同的类型update()(这里是努力的投票;)).
我相信没有HList或类似的数据结构是不可能的,因为统一汽车和公共汽车迫使我们使用车辆类型,它失去了关于其底层类型是汽车,公共汽车还是其他东西的信息(我们只能知道它是一些类型_ <: 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)
Run Code Online (Sandbox Code Playgroud)
我认为从这个答案中得到的主要内容是,这可以让您阐明Vehicle类型构造函数的递归性质。
我不确定我会推荐这个......
| 归档时间: |
|
| 查看次数: |
323 次 |
| 最近记录: |