を書きました。
たとえば
こんな trait があるときに
trait Sample{
def value1: Int
def value2: String
def value3: List[String]
}
こんなふうに書けるようになります
def Sample = TypeFactory[Sample]
val x = Sample(
value1 = 123,
value2 = "hello",
value3 = List("abc")
)
x.value2//hello
継承していても
こんな trait に対して
trait SubSample extends Sample with SampleTrait{
def value4: Double
}
trait SampleTrait {
def value5: Int
}
同じように書けます
def SubSample = TypeFactory[SubSample]
val x = SubSample(
value1 = 345,
value2 = "world",
value3 = List("def"),
value4 = 1.23,
value5 = 567
)
x.value5//567
ベンリですね
やってること
package x7c1.salad.factory
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
object TypeFactory {
def apply[A]: Any = macro TypeFactoryImpl.factory[A]
}
object TypeFactoryImpl {
def factory[A: c.WeakTypeTag](c: whitebox.Context) = {
import c.universe._
val klass = weakTypeOf[A]
val pairs = klass.members.
filter(_.isMethod).filter(_.isAbstract).map(_.asMethod).
map {
method => method.name -> method.typeSignatureIn(klass)
} collect {
case (term, NullaryMethodType(resultType)) => term -> resultType
}
val inner = {
val tuples = pairs.zipWithIndex.map{ case ((term, _), index) =>
term -> TermName("$x" + index)
}
val values = tuples.map{ case (term, tmp) =>
q"val $tmp = $term"
}
val methods = tuples.map{ case (term, tmp) =>
q"def $term = $tmp"
}
q"{ ..$values; new $klass { ..$methods } }"
}
val parameters = pairs.map{ case (term, resultType) =>
q"$term:$resultType"
}
val code = q"new { def apply(..$parameters) = $inner }"
/*
println(showRaw(code))
println(showCode(code))
// */
code
}
}
注意点
- まだ whitebox macro はしばらく experimental 扱い
-
Blackbox and whitebox macros
- 仕様が変わって将来つかえなくなる可能性アリ
-
Blackbox and whitebox macros
- Intellij さんも真っ赤
- マクロ展開してくれないから引数名の補完とか効かない
カナシス