3

我有两个特征,每个特征都有一个为其成员之一的类型参数。在第一个特征中,我有一个函数,它采用第二个特征的实例和第二个特征的类型成员的实例。此函数调用第二个特征中的函数,该函数期望其类型成员的该实例。但是,我无法弄清楚如何正确参数化调用以使其真正起作用。这是一个失败的简化示例:

trait Garage {
  type CarType <: Car
  def Cars: Seq[CarType]

  def copy(Cars: Seq[CarType]): Garage

  def Refuel(car: CarType, fuel: CarType#FuelType): Garage = {
    val car_index = Cars.zipWithIndex.find(_._1 == car).get._2

    copy(Cars.updated(car_index, car.Refuel(fuel)))
  }
}

trait Car {
  type FuelType <: Fuel
  def Fuel: FuelType

  def copy(Fuel: FuelType): Car

  def Refuel(fuel: FuelType): Car = {
    copy(fuel)
  }
}

trait Fuel

这失败并出现以下错误:

error: type mismatch;
 found   : fuel.type (with underlying type Garage.this.CarType#FuelType)
 required: car.FuelType
    copy(Cars.updated(car_index, car.Refuel(fuel)))
                                            ^

如何约束Garage.Refuel函数以使其接受 aCar以及Fuel该类型可接受的任何Car

4

2 回答 2

7

尝试:

def Refuel(car: CarType)(fuel: car.FuelType): Garage = {
于 2012-06-28T00:26:15.647 回答
4

尽管丹尼尔的回答有效,但我想指出一个替代方案,这是我自己的灵丹妙药。我一直在努力使路径依赖类型正确,并最终采用了以下策略。这有点“丑陋”,因为您现在需要编写一个额外的类型参数,但这种方法从未让我失望:

trait Garage {
  type CarType <: Car[CarType]  // CarType appears as representation type on the right
  def cars: Seq[CarType]

  def copy(Cars: Seq[CarType]): Garage

  def refuel(car: CarType, fuel: CarType#FuelType): Garage = copy(
    cars.map {  // map is more concise for what you try to achieve
      case `car` => car.refuel(fuel)  // backticks to find the particular car
      case other => other
    })
}

trait Car[C <: Car[C]] {  // add a 'representation type'
  type FuelType <: Fuel
  def fuel: FuelType

  // use 'C' instead of 'Car' everywhere, and qualify the type member with 'C#'
  def copy(fuel: C#FuelType): C

  def refuel(fuel: C#FuelType): C = copy(fuel)
}

trait Fuel

我不知道这个“表示类型”概念是否有正式名称(我很想知道)。我试图查找是谁教我的,但没有找到(至少在 stackoverflow 中)。

于 2012-06-28T01:40:52.390 回答