2016-11-23 67 views
1

我试图在Scala中实现类型类的一个复杂的例子:将T类型的值转换为字符串,实现为用户可以为任何类型T扩展的库。所以,这里是traits的所有类型类应该实现:从子类中导入implicits

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

我们要打电话做工作的功能:

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

对象与一些默认类型(仅诠释&这儿很久为例)一系列类型类:

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?
  • 对于一批用户提供的类型类是否有更好的解决方案?
+0

你可以看看[simulacrum](https://github.com/mpilquist/simulacrum)中的类型类。 –

回答

2

如果你事先知道你的代码需要PrintableFloatDouble那么你可能会直接把它声明:

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