从子类导入implicits

时间:2016-11-23 10:35:35

标签: scala implicit

我试图在Scala中实现一些复杂的类型类示例:将类型T的值转换为实现为库的字符串,用户可以为任何类型T扩展。所以这里的所有特性类型应该实现:

trait Printable[T] {
  def asString(value: T): String
}

我们打电话来完成这项工作的功能:

object Printer {
  def print[T](value: T)(implicit p:Printable[T]): String = p.asString(value)
}

具有一系列类型的对象,用于某些默认类型(例如,只有int& long):

object SimpleFormats extends Formats

trait Formats {
  implicit val intFormat = new Printable[Int] {
    override def asString(value: Int) = value.toString
  }
  implicit val longFormat = new Printable[Long] {
    override def asString(value: Long) = value.toString
  }
}

想象一下,用户想要扩展我们的库以用于其他类型,例如Float和Double。所以他创建了另一个对象,继承了第一个对象。这里的想法是向基础对象添加新的隐式成员,因此可以为任意数量的用户提供的类型扩展默认的类型类集合:

object ExtendedFormats extends Formats {
  implicit val floatFormat = new Printable[Float] {
    override def asString(value: Float) = value.toString
  }
  implicit val doubleFormat = new Printable[Double] {
    override def asString(value: Double) = value.toString
  }
}

最后,主应用程序使用我们的库。有两个示例函数在不同类型上执行操作,因此无法提供单个特定的隐式Printer[T]

  • 多种类型有多种操作
  • Printer事先不知道用户可以提供哪些类型。

所以主应用程序看起来像这样:

object Example {
  // compiles OK, uses only default typeclasses
  def simpleExample(implicit formats: Formats) = {
    import formats._
    Printer.print(42) + Printer.print(24L)
  }

  // compilation failed, cannot find Printable[Float]
  // uses user-supplied formats
  def extendedExample(implicit formats: Formats) = {
    import formats._
    Printer.print(42f) + Printer.print(31337.0)
  }

  def main(args: Array[String]): Unit = {
    implicit val formats = ExtendedFormats
    println(simpleExample)
    println(extendedExample)
  }
}

我看到scala编译器试图从Formats导入implicits,而忽略了它实际上是ExtendedFormats的事实。

问题:

  • 有没有办法从子类中导入implicits,如示例中所述?
  • 对于一批用户提供的类型类,是否有更好的解决方案?

1 个答案:

答案 0 :(得分:2)

如果您提前知道您的代码需要Printable FloatDouble,那么您可以直接声明:

def extendedExample(implicit floatPrintable: Printable[Float], doublePrintable: Printable[Double]) = {
  Printer.print(42f) + Printer.print(31337.0)
}

或创建Format的集合 - 类似特征:

trait FormatDouble {
  implicit val doubleFormat: Printable[Double]
}

然后用它来指定你需要的类型:

def extendedExample(implicit formats: Formats with FormatDouble with FormatFloat) = {
  import formats._
  Printer.print(42f) + Printer.print(31337.0)
}