Я хотел бы определить общий неявный преобразователь, который работает для всех подтипов типа T
.Например:
abstract class Price[A] {
def price(a: Any): Int
}
trait Car
case class Prius(year: Int) extends Car
trait Food
case class FriedChicken() extends Food
object Def {
implicit def carToPrice[A <: Car](car: A): Price[A] = new Price[A] {
def price(car: Any) = 100
}
implicit def foodToPrice[A <: Food](food: A): Price[A] = new Price[A] {
def price(food: Any) = 5
}
// implicit object PriusPrices extends Price[Prius] {
// def price(car: Any) = 100
// }
//
// implicit object FriedChickenPrices extends Price[FriedChicken] {
// def price(food: Any) = 5
// }
}
import Def._
def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit p: Price[A]) = (stuff, p) :: list
val stuff = add(Prius(2000), add(FriedChicken(), Nil))
stuff map { x => x._2.price(x._1) }
Приведенный выше код выдает ошибку:
error: could not find implicit value for parameter p: Price[FriedChicken]
val stuff = add(Prius(2000), add(FriedChicken(), Nil))
^
Что я делаю не так?
Обновление :
Как указывало @ extempore , неправильно то, что я путаю неявные преобразования (границы просмотра) и границы контекста (оба используют неявные параметры).Нет ничего плохого в моих общих неявных преобразователях.Проблема в том, что add
использует границы контекста вместо представления.Таким образом, мы можем исправить это следующим образом:
def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit view: A => Price[A]) = (stuff, view(stuff)) :: list
Интересная вещь, которую @extempore демонстрирует в своем коде, заключается в том, что нам не нужен универсальный конвертер, если Price[A]
был контравариантным.По сути, я могу заставить Price[Car]
работать от имени Price[Prius]
, что, как я и хотел.Таким образом, альтернативная версия с привязкой к контексту:
abstract class Price[-A] {
def price(a: Any): Int
}
implicit object CarPrice extends Price[Car] {
def price(a: Any) = 100
}
implicit object FoodPrice extends Price[Food] {
def price(a: Any) = 1
}
Related :