我想定义一个适用于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),Nil)) ^
我究竟做错了什么?
更新:
正如@extempore所指出的那样,错误的是我混淆了隐式转换(视图边界)和上下文边界(两者都使用了隐式参数).我的通用隐式转换器没有任何问题.问题是add使用上下文边界而不是视图.所以我们可以修复如下:
def add [A,Price[_])])(implicit view: A => Price[A]) = (stuff,view(stuff)) :: list
@extempore在他的代码中演示的一个有趣的事情是,如果Price [A]是逆变的,我们真的不需要通用的转换器.基本上,我可以代价Price [Prius]使Price [Car]工作,这是我想要的.所以替代的上下文绑定版本是:
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 }
有关:
解决方法
你真正想要的并不是很清楚.您确实混合了隐式转换和隐式参数.我没有尝试解决它,而是编写了一些代码.
object Test { type Price = Int abstract class Pricable[-A] { def price(a: A): Price } trait Car case class Prius(year: Int) extends Car trait Food case class FriedChicken() extends Food implicit val CarPricingGun = new Pricable[Car] { def price(a: Car): Price = 100 } implicit val FoodPricingGun = new Pricable[Food] { def price(a: Food): Price = 1 } implicit def priceableItemToPrice[A: Pricable](x: A) = implicitly[Pricable[A]] price x def main(args: Array[String]): Unit = { val x1 = Prius(2000) val x2 = FriedChicken() println("Price of " + x1 + " is " + (x1: Price)) println("Price of " + x2 + " is " + (x2: Price)) } } // Output is: // // Price of Prius(2000) is 100 // Price of FriedChicken() is 1 //