scala - 解析 F 有界多态性中的类型

标签 scala generics 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() }

如果我获得 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] .但是,如果我撕掉一个存在类型,我就无能为力了。前面的例子有效,因为 CarVehicle[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/

相关文章:

scala - 如何用akka-http将字节流解析为 `HttpRequest`对象?

scala - 使用 Spark 读取欧洲格式的 .csv 数据

java - 泛型并在 Java 中转换

java - Kotlin 通用反射子类

scala - 为什么 Scala 无法对 f 绑定(bind)多态性进行类型推断?

scala - 使用 Scala 在 Spark 中创建映射值

string - 如何在scala中将长十六进制字符串转换为BigInt

Java 通用类的可分配性

scala - 在 Scala 中绑定(bind)引用自身的类型是什么意思?

scala - 尝试将 F 有界多态性建模为 Scala 中的类型成员