這是表示類型的twoquestions的後續操作,表示類型是設計用於表示有界類型成員(或類似東西)的基礎類型的類型參數, 。我已經成功地創建了類的實例,例如ConcreteGarage
,它們的實例有cars
有界類型成員CarType
。Scala:通過if語句更正表示類型的類型推斷
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
我可以很容易地像Ferrari
S和Mustang
S創建的Car
小號實例,並把它們放入一個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]]
表示類型參數無處不在,但沒有找到魔法點成功。
我知道我應該聽從你的早期警告關於表示類型。你的答案的後半部分似乎是解決這個問題的方法。要選擇'Make'-'Fuel'組合的一個子集,可以設置類型別名,比如'MustangCar = Car [Mustang,Benzin]'或者CarWithBenzin = Car [Make,Benzin]'。對於我真正的項目(不幸的是不涉及賽車野馬),這應該是有用的。 – drhagen
請注意,表示類型並不是問題 - 整個Scala集合庫成功使用它們而沒有「感染」其他任何東西;真正的問題在於使用路徑依賴類型構建可擴展的東西。當您將多種類型組合在一起時,「世界」方法可能很有用,但我不確定是否屬於這種情況。 –