Scala:通用隐式转换器?

标签 scala implicit typeclass

我想定义一个通用的隐式转换器,它适用于 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指出,错在我混淆了隐式转换( View 边界)和上下文边界(两者都使用隐式参数)。我的通用隐式转换器没有任何问题。问题是 add正在使用上下文边界而不是 View 。所以我们可以修复如下:
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] 工作,这正是我想要的。所以替代的上下文绑定(bind)版本是:
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
}

相关 :
  • [scala] Generic implicit converters?
  • 最佳答案

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

    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
    // 
    

    关于Scala:通用隐式转换器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3843543/

    相关文章:

    scala - 为什么 `.asInstanceOf` 有时会抛出,有时不会?

    java - 如何在scala中生成protobuf?

    scala - 我可以在 Scala 案例类中使用隐式转换方法吗?

    haskell - 用可变变量表示数据类型

    haskell - ClassyPrelude 中两个独立 map 函数的基本原理

    scala - Scala 中的基本集合类型是什么?

    Scala 枚举在 java 中的使用

    scala - 给定关键字在 Scala 3 或 dotty 中如何工作?

    scala - 隐式参数的有效用法

    haskell - 对 Haskell 中类型类和变量赋值的误解