我大量使用Pimp my Library模式,我想删除样板文件。例如,假设我有一些特质PrettyPrint:
trait PrettyPrint { def prettyPrint: String }
如果我想要pimp Int和Double,我需要编写这样的代码:
implicit def int2PrettyPrint(self: Int) =
new PrettyPrint { def prettyPrint = "Int: " + self }
implicit def double2PrettyPrint(self: Double) =
new PrettyPrint { def prettyPrint = "Double: " + self }
在上面,我将其归类为样板:1)隐式转换的名称,2)“new”关键字,3)也许参数名称为“self”,4)也许是“隐含”关键字。我宁愿写这样的东西:
@pimp[Int, PrettyPrint] { def prettyPrint = "Int: " + self }
@pimp[Double, PrettyPrint] { def prettyPrint = "Double: " + self }
在上面代码的右侧,假设名称“self”是转换参数。
关于如何做到这一点的想法?
一些注意事项:
1)如果需要,我可以使用Scala 2.10。
2)据我所知,Scala 2.10 中的新隐式类不足以。这是因为每个隐式类只有一个隐式转换。换句话说,像下面这样的代码无法编译,因为PrettyPrint被声明了两次:
implicit class PrettyPrint(self: Int) = ...
implicit class PrettyPrint(self: Double) = ...
答案 0 :(得分:3)
您可以用不同的方式命名隐式类:
implicit class PrettyPrintInt(self: Int) = ...
implicit class PrettyPrintDouble(self: Double) = ...
答案 1 :(得分:3)
这是另一种解决方案,需要更多的样板预先设置,以换取PrettyPrint
的每个特定实例的稍微混乱:
implicit class PrettyPrintable[T]( val self: T ) extends AnyVal {
def prettyPrint( implicit impl: PrettyPrint[T]): String = impl.prettyPrint( self )
}
trait PrettyPrint[T]{ def prettyPrint( self: T ): String }
object PrettyPrint {
def apply[T]( impl: T => String ): PrettyPrint[T] = new PrettyPrint[T] {
def prettyPrint( self: T ) = impl( self )
}
}
implicit val int2PrettyPrint = PrettyPrint[Int]( "Int: " + _ )
implicit val double2PrettyPrint = PrettyPrint[Double]( "Double: " + _ )
// Or more explicitly:
//implicit val int2PrettyPrint = PrettyPrint{self: Int => "Int: " + self }
//implicit val double2PrettyPrint = PrettyPrint{self: Double => "Double: " + self }
比较
implicit def int2PrettyPrint(self: Int) = new PrettyPrint { def prettyPrint = "Int: " + self }
为:
implicit val int2PrettyPrint = PrettyPrint[Int]( "Int: " + _ )
您仍然需要implicit
关键字,以及隐含值的唯一名称
答案 2 :(得分:2)
对NativeLibs4Java邮件列表中discussion的后续跟踪,我在其中举例说明了such a compiler plugin(将@extend(Int) def foo = blah
扩展为implicit class foo(self: Int) extends AnyVal { def foo = blah }
)。
我写了a more elaborated plugin,将这些定义扩展为......宏(提供宏扩展扩展/“pimps”,没有运行时依赖!)。
假设:
@extend(Any) def quoted(quote: String): String = quote + self + quote
它扩展为:
import scala.language.experimental.macros
implicit class scalaxy$extensions$quoted$1(self: Any) {
def quoted(quote: String) = macro scalaxy$extensions$quoted$1.quoted
}
object scalaxy$extensions$quoted$1 {
def quoted(c: scala.reflect.macros.Context)
(quote: c.Expr[String]): c.Expr[String] = {
import c.universe._
val Apply(_, List(selfTree$1)) = c.prefix.tree
val self = c.Expr[Any](selfTree$1)
{
reify(quote.splice + self.splice + quote.splice)
}
}
}
答案 3 :(得分:1)
1周后的摘要:看来我需要编写一个编译器插件来获取我指定的确切行为。