解决类型我有这些模型:在F-界多态性
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]
(或简单地说,汽车是一个汽车[汽车]),我可以放心地明确设置结果的类型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-bound类型)。使用存在类型砸了类型的关系,因为一旦我从车辆获取潜在汽车/公交车,我再也不能将它转换为车辆因为......好吧,这只是一些存在类型:
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[_]
。
要指定我的具体问题:对于上面给出的模型(车辆,汽车,公交车),有没有办法实现这一点?
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
可以解决这个问题,因为我不需要使用存在类型(我只是简单地列出了一辆汽车和一辆公交车,并且该类型的信息将被保留)。但是我想用这个简单的List
这个特殊的用例。
编辑:
@RomKazanova是,将工作,当然,但我需要之前和之后update()
保留同一类型(这里所付出的努力的给予好评,虽然;))。
我相信,如果没有HList或类似的数据结构,这是不可能的,因为统一的汽车和公共汽车迫使我们使用车型,这种车型会丢失其底层类型是汽车,公交车还是别的东西(我们可以知道的是这是一些类型_ <: Vehicle
)。但我想和你们核对一下。
我本来以为'列表[汽车[_ <:汽车[_]]]'是同一类型'名单[汽车[ T] forSome {type T <:Vehicle [T]}]'。作为一般的经验法则,我并不介意在任何地方使用'forSome',但我听说它被Scala 2.13或2.14驱逐。无论如何,非常感谢你,这正是我期待的那种解决方案。 – slouc
我确实从我的REPL记录中删除了所有的存在类型警告。所以我认为这是一种只有通配符才能表达的存在感。我不确定*如果*它会被完全删除,但如果是的话,我认为最快的时候会是Dotty变成Scala 3.0或类似的东西。 –
顺便说一句,我意外地低估了你:)固定 – slouc