LoginSignup
8
8

More than 5 years have passed since last update.

Scala で trait のファクトリを生成してくれるマクロ

Last updated at Posted at 2014-08-11

を書きました。

たとえば

こんな 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

ベンリですね

やってること

github : TypeFactory.scala

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 扱い
  • Intellij さんも真っ赤
    • マクロ展開してくれないから引数名の補完とか効かない

カナシス

参考

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8