如何在scala宏中获取复杂类型?

问题描述

我有以下宏,它正在为源类的给定访问器构造一些 Field 类:

case class Field[S,F](name: String,lens: Lens[S,F])

class Fields[S] {
  def field[D](property: S => D): Field[S,D] = macro FieldsMacro.impl[S,D]
}

class FieldsMacro(val c: whiteBox.Context) {

  import c.universe._

  def impl[S: c.WeakTypeTag,D: c.WeakTypeTag](property: c.Expr[S => D]): c.Expr[Field[S,D]] = {
    val sourceType = weakTypeOf[S]
    val destinationType =  weakTypeOf[D]

    val field = sourceType.decls.collect {
      case m: MethodSymbol if m.isCaseAccessor =>
        val methodName = m.name.decodedname.toString
        val q"($x) => $x2.$name" = property.tree
        if (name.toString().equals(methodName)) {
          Some(q"Field($methodName,Lens[${sourceType.typeSymbol},${destinationType.typeSymbol}]($property)(_ => x => x))")
        } else None
    }.filter(_.isDefined).map(_.get).head

    val result =
      q"""
        //some imports

        $field
       """
    println(showCode(result))
    c.Expr[Field[S,D]](result)
  }
}

用法示例:

case class TestClass(i: Int,s: String,seq: Seq[Int])

object TestObject extends Fields[TestClass] {
  val i = field[Int](_.i)
  val seq = field[Seq[Int]](_.seq)
}

问题在于 weakTypeOf[D] 返回 Seq 而不是所需的 Seq[Int]。所以我需要在像 Map[String,Int]List[Option[SomeClass]] 这样的宏中传递复杂的完整类型,所以我可以用准引号替换它。

解决方法

我只需要删除 .typeSymbol 调用

class FieldsMacro(val c: whitebox.Context) {

  import c.universe._

  def impl[S: c.WeakTypeTag,D: c.WeakTypeTag](property: c.Expr[S => D]): c.Expr[Field[S,D]] = {
    val sourceType = weakTypeOf[S]
    val destinationType =  weakTypeOf[D]

    val field = sourceType.decls.collect {
      case m: MethodSymbol if m.isCaseAccessor =>
        val methodName = m.name.decodedName.toString
        val q"($x) => $x2.$name" = property.tree
        if (name.toString().equals(methodName)) {
          Some(q"Field($methodName,Lens[${sourceType},${destinationType}]($property)(_ => x => x))")
        } else None
    }.filter(_.isDefined).map(_.get).head

    val result =
      q"""
        import com.github.nikodemin.validation.Validators.Field
        import com.github.nikodemin.validation.Fields
        import monocle.Lens

        $field
       """
    println(showCode(result))
    c.Expr[Field[S,D]](result)
  }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...