scala - 将值插入 quasiquote
scala - insert value into quasiquote
不幸的是,最直观的方式,
val world = "Earth"
val tree = q"""println("Hello $world")"""
结果
Error:(16, 36) Don't know how to unquote here
val tree = q"""println("Hello $world")"""
^
因为 $
在 quasiquotes 中需要一个 tree
.
val world = "Earth"
val tree = q"""println(${c.literal(s"Hello $world")})"""
有效,但非常丑陋,我收到 Intellij 警告,指出 c.literal
已弃用,我应该使用准引号。
那么...我该怎么做?
更新
回复 flavian 的评论:
import scala.language.experimental.macros
import scala.reflect.macros._
object TestMacros {
def doTest() = macro impl
def impl(c: blackbox.Context)(): c.Expr[Unit] = {
import c.universe._ //access to AST classes
/*
val world = "Earth"
val tree = q"""println(${c.literal(s"Hello $world")})"""
*/
val world = TermName("Earth")
val tree = q"""println("Hello $world")"""
tree match {
case q"""println("Hello Earth")""" => println("succeeded")
case _ => c.abort(c.enclosingPosition, s"huh? was: $tree")
}
c.Expr(tree) //wrap tree and tag with its type
}
}
给予
Error:(18, 40) Don't know how to unquote here
val tree = q"""println("Hello $world")"""
^
您需要 TermName
或编译器原语。
真正的问题是你在混合插值器,却没有意识到。 hello world 中的插值器实际上是一个字符串插值器,而不是像你建议的那样擅长取消引用树的准引用器。
这是一种解决方法:
import c.universe._
val world = TermName("Earth")
val tree = q"""println("Hello" + ${world.decodedName.toString})"""
刚开始学宏赋
对于那些也在探索 Scala 2 Macros / Scalameta Quasiquotes 的人,在我看来最简单的方法如下(使用 SBT 1.5.5;内联解释):
scala> import scala.language.experimental.macros
| import scala.reflect.macros.blackbox
|
| object UnquoteString {
|
| def helloWorld(): Unit = macro Impl.helloWorld
|
| object Impl {
| def helloWorld(c: blackbox.Context)(): c.Expr[Unit] = {
| import c.universe._
|
| val world = "Earth" // or any other value here...
|
| val msg = s"Hello $world" // build the entire string with it here...
|
| implicitly[Liftable[String]] // as we can lift 'whole' string values with this Liftable[_]...
|
| val tree = q"""println($msg)""" // quasi-unquote the entire string here...
|
| c.Expr[Unit](Block(Nil, tree))
| }
| }
| }
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object UnquoteString
scala> UnquoteString.helloWorld()
Hello Earth
scala>
另外,以下更改也有效
val tree = q"""println("Hello, " + $world)""" // quasi-unquote the string to append here...
不幸的是,最直观的方式,
val world = "Earth"
val tree = q"""println("Hello $world")"""
结果
Error:(16, 36) Don't know how to unquote here
val tree = q"""println("Hello $world")"""
^
因为 $
在 quasiquotes 中需要一个 tree
.
val world = "Earth"
val tree = q"""println(${c.literal(s"Hello $world")})"""
有效,但非常丑陋,我收到 Intellij 警告,指出 c.literal
已弃用,我应该使用准引号。
那么...我该怎么做?
更新
回复 flavian 的评论:
import scala.language.experimental.macros
import scala.reflect.macros._
object TestMacros {
def doTest() = macro impl
def impl(c: blackbox.Context)(): c.Expr[Unit] = {
import c.universe._ //access to AST classes
/*
val world = "Earth"
val tree = q"""println(${c.literal(s"Hello $world")})"""
*/
val world = TermName("Earth")
val tree = q"""println("Hello $world")"""
tree match {
case q"""println("Hello Earth")""" => println("succeeded")
case _ => c.abort(c.enclosingPosition, s"huh? was: $tree")
}
c.Expr(tree) //wrap tree and tag with its type
}
}
给予
Error:(18, 40) Don't know how to unquote here
val tree = q"""println("Hello $world")"""
^
您需要 TermName
或编译器原语。
真正的问题是你在混合插值器,却没有意识到。 hello world 中的插值器实际上是一个字符串插值器,而不是像你建议的那样擅长取消引用树的准引用器。
这是一种解决方法:
import c.universe._
val world = TermName("Earth")
val tree = q"""println("Hello" + ${world.decodedName.toString})"""
刚开始学宏赋
对于那些也在探索 Scala 2 Macros / Scalameta Quasiquotes 的人,在我看来最简单的方法如下(使用 SBT 1.5.5;内联解释):
scala> import scala.language.experimental.macros
| import scala.reflect.macros.blackbox
|
| object UnquoteString {
|
| def helloWorld(): Unit = macro Impl.helloWorld
|
| object Impl {
| def helloWorld(c: blackbox.Context)(): c.Expr[Unit] = {
| import c.universe._
|
| val world = "Earth" // or any other value here...
|
| val msg = s"Hello $world" // build the entire string with it here...
|
| implicitly[Liftable[String]] // as we can lift 'whole' string values with this Liftable[_]...
|
| val tree = q"""println($msg)""" // quasi-unquote the entire string here...
|
| c.Expr[Unit](Block(Nil, tree))
| }
| }
| }
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object UnquoteString
scala> UnquoteString.helloWorld()
Hello Earth
scala>
另外,以下更改也有效
val tree = q"""println("Hello, " + $world)""" // quasi-unquote the string to append here...