これは、表現型に関する2つの 質問のフォローアップです。これらは、有界型メンバー(またはそのようなもの)の基礎となる型を表すように設計されたトレイトの型パラメーターです。有界型メンバーのConcreteGarage
インスタンスを持つクラスのインスタンスを作成することに成功しました。cars
CarType
trait Garage {
type CarType <: Car[CarType]
def cars: Seq[CarType]
def copy(cars: Seq[CarType]): Garage
def refuel(car: CarType, fuel: CarType#FuelType): Garage = copy(
cars.map {
case `car` => car.refuel(fuel)
case other => other
})
}
class ConcreteGarage[C <: Car[C]](val cars: Seq[C]) extends Garage {
type CarType = C
def copy(cars: Seq[C]) = new ConcreteGarage(cars)
}
trait Car[C <: Car[C]] {
type FuelType <: Fuel
def fuel: FuelType
def copy(fuel: C#FuelType): C
def refuel(fuel: C#FuelType): C = copy(fuel)
}
class Ferrari(val fuel: Benzin) extends Car[Ferrari] {
type FuelType = Benzin
def copy(fuel: Benzin) = new Ferrari(fuel)
}
class Mustang(val fuel: Benzin) extends Car[Mustang] {
type FuelType = Benzin
def copy(fuel: Benzin) = new Mustang(fuel)
}
trait Fuel
case class Benzin() extends Fuel
単純である限り、sやsCar
のようなsのインスタンスを簡単に作成し、それらをに入れることができます。Ferrari
Mustang
ConcreteGarage
val newFerrari = new Ferrari(Benzin())
val newMustang = new Mustang(Benzin())
val ferrariGarage = new ConcreteGarage(Seq(newFerrari))
val mustangGarage = new ConcreteGarage(Seq(newMustang))
ただし、フラグに基づいてどちらか一方を返すだけで、その結果をガレージに入れようとすると、失敗します。
val likesFord = true
val new_car = if (likesFord) newFerrari else newMustang
val switchedGarage = new ConcreteGarage(Seq(new_car)) // Fails here
スイッチだけで正常にConcreteGarage
機能します。コンストラクターの呼び出しが失敗し、かなり神秘的なエラーが発生します。
error: inferred type arguments [this.Car[_ >: this.Ferrari with this.Mustang <: this.Car[_ >: this.Ferrari with this.Mustang <: ScalaObject]{def fuel: this.Benzin; type FuelType<: this.Benzin}]{def fuel: this.Benzin; type FuelType<: this.Benzin}] do not conform to class ConcreteGarage's type parameter bounds [C <: this.Car[C]]
val switchedGarage = new ConcreteGarage(Seq(new_car)) // Fails here
^
私はそれらの魔法の[C <: Car[C]]
表現タイプのパラメータをどこにでも配置しようとしましたが、魔法の場所を見つけることに成功しませんでした。