2

我正在尝试制作一个提供更新案例类的类型提供程序。

我如何拼接类型和默认值(或省略默认值)?

def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    import Flag._

    val result = {
      annottees.map(_.tree).toList match {
        case q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$body }" :: Nil =>
          val valType    = //TODO
          val valDefault = //TODO
          val helloVal   = q"""val x: $valType = $valDefault"""
          q"$mods class $name[..$tparams](..$first, $helloVal)(...$rest) extends ..$parents { $self => ..$body }"
      }
    }
    c.Expr[Any](result)
  }

我试过了:

我试过val valType = q"String"了,但是我得到一个错误,好像没有找到默认值:not enough arguments for method apply

我也尝试在定义为的 val 中进行拼接typeOf[String],并且我也尝试将ValDefs 的列表拼接到我的q"$mods class...(就像我q"def...在本网站上的一些类似问题中看到的那样),但在每种情况下都有一个打字机错误

有小费吗?非常感谢您的关注。

4

1 回答 1

2

您可以tq在定义中使用插值器valType来创建类型树。

其余的有点棘手。如果您直接定义额外的参数,它似乎工作得很好:

q"""
  $mods class $name[..$tparams](
    ..$first,
    val x: $valType = $valDefault
  )(...$rest) extends ..$parents { $self => ..$body }
"""

但是,当您定义$helloVal然后将其插入时,您最终会没有默认参数标志。你可以写一个这样的助手:

def makeDefault(valDef: ValDef) = valDef match {
  case ValDef(mods, name, tpt, rhs) => ValDef(
    Modifiers(
      mods.flags | DEFAULTPARAM, mods.privateWithin, mods.annotations
    ),
    name, tpt, rhs
  )
}

现在您可以编写以下内容:

val valType    = tq"String"
val valDefault = q""""foo""""
val helloVal   = makeDefault(q"val x: $valType = $valDefault")

一切都应该按预期工作。

于 2014-01-11T15:14:07.420 回答