ケースクラスのインスタンスを引数として取るScalaマクロをプログラムしたいと思います。マクロに渡すことができるすべてのオブジェクトは、特定のマーカー特性を実装する必要があります。
次のスニペットは、マーカー特性とそれを実装する2つのケースクラスの例を示しています。
trait Domain
case class Country( id: String, name: String ) extends Domain
case class Town( id: String, longitude: Double, latitude: Double ) extends Domain
ここで、実行時の反映の重さとそのスレッドの安全性を回避するために、マクロを使用して次のコードを記述したいと思います。
object Test extends App {
// instantiate example domain object
val myCountry = Country( "CH", "Switzerland" )
// this is a macro call
logDomain( myCountry )
}
マクロlogDomain
は別のプロジェクトに実装されており、次のようになります。
object Macros {
def logDomain( domain: Domain ): Unit = macro logDomainMacroImpl
def logDomainMacroImpl( c: Context )( domain: c.Expr[Domain] ): c.Expr[Unit] = {
// Here I would like to introspect the argument object but do not know how?
// I would like to generate code that prints out all val's with their values
}
}
マクロの目的は、実行時に、指定されたオブジェクトのすべての値(id
および)を出力し、次に示すようにそれらを出力するコードを生成することです。name
id (String) : CH
name (String) : Switzerland
これを実現するには、渡された型引数を動的に検査し、そのメンバー(vals)を決定する必要があります。次に、ログ出力を作成するコードを表すASTを生成する必要があります。マクロは、マーカー特性「ドメイン」を実装する特定のオブジェクトがマクロに渡されるかどうかに関係なく機能する必要があります。
この時点で私は迷子になっています。誰かが私に出発点を教えてくれたり、いくつかのドキュメントを教えてくれたら幸いです。私はScalaに比較的慣れていないので、ScalaAPIドキュメントまたはマクロガイドで解決策を見つけられませんでした。