加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-16 09:55:58 所属栏目:安全 来源:网络整理
导读:我有这些模型: 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(),我将获得一辆
我有这些模型:

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 [_]](具有简单车辆列表[_]和在元素上调用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

因此,Vehicle用一些类型T参数化,这是Vehicle [T]的子类型.当我撕掉T(通过使用update())时,如果是具体的类型,它就可以了 – 例如如果我扯掉汽车,我可以安全地声称我扯掉了一辆汽车[汽车],因为汽车<:车辆[汽车].但如果我撕掉一个存在主义类型,我就无法做任何事情.之前的例子有效,因为Car是一辆车[Car],但在这种情况下_不是车辆[_]. 指定我的具体问题:对于上面给出的模型(车辆,汽车,公共汽车),有没有办法实现这一目标?

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()之前和之后保留相同的类型(虽然这是努力的一个upvote;)).

我相信没有HList或类似的数据结构是不可能的,因为统一汽车和公共汽车迫使我们使用车辆类型,它失去了关于其底层类型是汽车,公共汽车还是其他东西的信息(我们只能知道它是一些type _&lt ;: Vehicle).但我想和你们一起检查一下.

解决方法

我对存在类型不是很好,所以我不能解释太多这个:-p但是当你将seq的类型改为List [Vehicle [T] forSome {type T<:Vehicle [T]}一切似乎都“锻炼”了.请注意,您必须将类型传递给List构造函数/ apply方法.

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类型构造函数的递归性质.

我不确定我会推荐这个……

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读