简体   繁体   English

从子类导入隐式

[英]Importing implicits from a subclass

I'm trying to implement a bit sophisticated example of typeclasses in Scala: convert value of type T to string implemented as a library a user can extends for any type T. So here's the trait all the typeclasses should implement: 我正在尝试在Scala中实现类型类的一些复杂示例:将类型T的值转换为字符串,该字符串实现为用户可以扩展为任何类型T的库。因此,这是所有类型类应实现的特征:

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

The function we're going to call to do the job: 我们要调用以完成工作的函数:

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

Object with a series of typeclasses for some default types (only int&long here for example): 具有用于某些默认类型的一系列类型类的对象(例如,仅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
  }
}

Imagine that the user wants to extend our library for some other type, like Float and Double. 想象一下,用户想要将我们的库扩展为其他类型,例如Float和Double。 So he creates another object, subclassing the first one. 因此,他创建了另一个对象,将第一个对象作为子类。 The idea here is to add new implicit members to the base object so the default collection of typeclasses can be extended for any number of user-supplied types: 这里的想法是向基础对象添加新的隐式成员,以便可以将类型类的默认集合扩展为任意数量的用户提供的类型:

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

And finally, the main app using our library. 最后,使用我们库的主应用程序。 There are two example functions doing operations on different types, so it's not possible to supply single specific implicit Printer[T] as: 有两个对不同类型进行操作的示例函数,因此无法提供单个特定的隐式Printer[T]

  • there are multiple operations on multiple types 有多种类型的多种操作
  • the Printer does not know beforehand which types may be supplied by the user. Printer事先不知道用户可以提供哪种类型。

So the main app looks like this: 因此主应用程序如下所示:

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)
  }
}

I see that scala compiler tries to import implicits from the Formats , ignoring the fact that it is ExtendedFormats actually. 我看到scala编译器尝试从Formats导入隐式数据,而忽略了它实际上是ExtendedFormats的事实。

Questions: 问题:

  • Is there a way to import implicits from a subclass as described in the example? 如示例中所述,是否可以从子类导入隐式方法?
  • Is there a better solution for a batch of user-supplied typeclasses? 有一批用户提供的类型类更好的解决方案吗?

If you know in advance that your code needs Printable for Float and for Double then you might declare it directly: 如果您事先知道您的代码需要Printable用于FloatDouble那么您可以直接声明它:

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

Or create a collection of Format -like traits: 或创建类似Format的特征的集合:

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

and then use it to specify what types do you need: 然后使用它指定所需的类型:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM