5

我想定义一个适用于 type 的所有子类型的通用隐式转换器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

Price[A]@extempore 在他的代码中展示的一件有趣的事情是,如果是逆变的,我们实际上并不需要通用转换器。基本上,我可以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
}

相关

4

3 回答 3

8

目前还不是很清楚你真正想要什么。您确实混淆了隐式转换和隐式参数。我没有尝试整理它,而是编写了一些代码。

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
// 
于 2010-10-02T04:16:59.500 回答
2

问题是您已经定义了从 a和值到s 的隐式carToPricefoodToPrice隐式方法,但是没有和值在您需要转换的地方是显而易见的。由于您实际上并未在这些隐式方法中使用参数,因此我认为您真正想要的是隐式,如下所示:CarFoodPriceCarFood

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
}
于 2010-10-01T23:28:20.257 回答
0

正如@extempore指出的那样,错误在于我混淆了隐式转换(视图边界)和上下文边界(两者都使用隐式参数)。我的通用隐式转换器没有任何问题。问题是add使用上下文边界而不是视图。所以我们可以修复如下:

def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit view: A => Price[A]) = (stuff, view(stuff)) :: list
于 2010-10-02T05:39:31.280 回答