只是将 val 添加到模板中不会自动使其成为构造函数参数。为此,构造函数本身也需要进行调整。幸运的是,我们有 quasiquotes,与手动构建树相比,它大大简化了这项任务。
case q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$body }" :: Nil =>
val CASEACCESSOR = (1 << 24).toLong.asInstanceOf[FlagSet]
val PARAMACCESSOR = (1 << 29).toLong.asInstanceOf[FlagSet]
val helloMods = Modifiers(CASEACCESSOR | PARAMACCESSOR | DEFAULTPARAM)
val helloVal = q"""$helloMods val x: String = "hello macro!""""
q"$mods class $name[..$tparams](..$first, $helloVal)(...$rest) extends ..$parents { $self => ..$body }"
注意几个怪癖:1)我们需要设置官方 API 中不存在的 CASEACCESSOR 和 PARAMACCESSOR 标志以避免在 Salat 中崩溃,2)我们需要设置 DEFAULTPARAM 以确保 scalac 识别我们的默认值参数作为默认值,3)默认参数不能推断出它们的类型,所以我们需要在这里显式地提供String。