【问题标题】:How to generalize scala type that works in Array如何概括适用于 Array 的 scala 类型
【发布时间】:2021-02-07 12:28:39
【问题描述】:

我有以下代码:

trait Vehicle {
  def regNumber: String
  def lotSize: Int
}
case class Car(regNumber: String) extends Vehicle {override val lotSize = 2}
case class Motorcycle(regNumber: String) extends Vehicle {override val lotSize = 1}

trait AbstractLot[+T <: Vehicle] {
  def vehicle: T
  def lotSize: Int = vehicle.lotSize
}
final case class CarLot(vehicle: Car) extends AbstractLot[Car]
final case class MotorcycleLot(vehicle: Motorcycle) extends AbstractLot[Motorcycle]

我想要一个ParkingLot 类型,它是一个抽象批次选项的数组。但是,当我写下面的代码时,Scala 编译器并不高兴

object ParkingLot {
  type ParkingLot = Array[Option[AbstractLot[_]]]

  //Case 1: OK
  def mixMotorcycleCar(motorcycleCapacity: Int, carCapacity: Int): ParkingLot =
    Array.fill[Option[MotorcycleLot]](motorcycleCapacity)(None) +: Array.fill[Option[CarLot]](carCapacity)(None)

  //Case 2: Not OK
  //T is a subclass of AbstractLot. Why isn't this working?
  def homogenous[T <: AbstractLot[_]](capacity: Int): ParkingLot = Array.fill[Option[T]](capacity)(None)

  //Case 3: Not OK
  def carOnly(capacity: Int): ParkingLot = Array.fill[Option[CarLot]](capacity)(None)

}

我做错了什么?我应该如何修复我的代码,以便我可以拥有适用于案例 2 和案例 3 的 ParkingLot 类型?

【问题讨论】:

  • 如果您不知道它是摩托车锁还是车辆锁,您希望如何使用每个批次?您需要重新设计它,使用 ADT (我会推荐这个) 或类型成员而不是类型参数。
  • 感谢您的回复。我相信设计会更好。但是,我不确定我是否遵循您的解释。在案例 1 中,可以有一个由 AbstractLot 引用的 MotorLot 和 CarLot 的混合数组。但是为什么我不能像案例 2 和案例 3 那样拥有一个由 AbstractLot 引用的数组 CarLot(仅)?
  • 正如@Ava 解释的由于不变性,这反过来又是由于可变性。这两个是为什么你不应该在 Scala 中使用普通的 Arrays 的原因,除非你真的需要它们来提高性能。我建议使用 ListVectorArraySeq 并确保您的解决方案是不可变的,使用 map 之类的东西来创建修改后的副本.
  • 感谢您的回答和建议。这对我的理解很有帮助!

标签: scala types


【解决方案1】:

这里的问题是可变集合在 Scala 中具有不变的元素类型,因此您不能在 Array[Option[AbstractLot[Any]]] 中存储 Option[CarLot]Option[MotorcycleLot] 元素。原因可以在这里找到:relation between variance and mutabilty / immutability in Scala

ParkingLot 对象主要用于空间预分配,这在 Scala 中很少需要。您必须重新考虑您的设计,因为不可能创建任何具有协变类型的可变集合。使用可变集合表示停车场的最简单方法是这样的:

val parkingLot = ArrayBuffer[Vehicle]()
parkingLot.addOne(Car("123"))
parkingLot.addOne(Motorcycle("321"))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多