【发布时间】:2010-10-01 23:00:10
【问题描述】:
我想定义一个适用于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
}
相关:
【问题讨论】: