2

Pimp my Libraryパターンを多用しており、ボイラープレートを削除したいと考えています。たとえば、PrettyPrint というトレイトがあるとします。

trait PrettyPrint { def prettyPrint: String }

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) おそらく "implicit" キーワード。私はむしろこのようなものを書きたい:

@pimp[Int, PrettyPrint] { def prettyPrint = "Int: " + self }
@pimp[Double, PrettyPrint] { def prettyPrint = "Double: " + self }

上記のコードの右側では、「self」という名前が変換引数であると想定されています。

これを行う方法についてのアイデアはありますか?

いくつかのメモ:

1) 必要に応じて Scala 2.10 を使用します。

2)私の知る限り、Scala 2.10 の新しい暗黙のクラスは十分ではありません。これは、暗黙的なクラスごとに暗黙的な変換が 1 つしかないためです。つまり、PrettyPrint が 2 回宣言されているため、次のようなコードはコンパイルされません。

implicit class PrettyPrint(self: Int) = ...
implicit class PrettyPrint(self: Double) = ...
4

4 に答える 4

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ただし、暗黙的な値の一意の名前だけでなく、キーワードも必要です

于 2012-11-05T11:17:28.083 に答える
3

暗黙のクラスに別の名前を付けることができます。

implicit class PrettyPrintInt(self: Int) = ...
implicit class PrettyPrintDouble(self: Double) = ...
于 2012-11-04T21:13:14.857 に答える
2

NativeLibs4Javaのメーリングリストに関するディスカッションのフォローアップ。ここでは、そのようなコンパイラプラグイン(に展開@extend(Int) def foo = blahされますimplicit class foo(self: Int) extends AnyVal { def foo = blah })の例を示しました。

これらの定義を...マクロに拡張する、より複雑なプラグインを作成しました(実行時の依存関係なしに、マクロ拡張可能な拡張機能/ "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)
    }
  }
}
于 2013-02-20T09:02:17.233 に答える
1

1週間後のまとめ:指定した正確な動作を取得するには、コンパイラプラグインを作成する必要があるようです。

于 2012-11-12T20:37:26.930 に答える