Scala 准引号提升
Scala Quasiquote Lifting
Quasiquotes 的 Scala 文档在解释时提到了这一点 Lifting:
One can also combine lifting and unquote splicing:
scala> val ints = List(1, 2, 3)
scala> val f123 = q"f(..$ints)"
f123: universe.Tree = f(1, 2, 3)
scala> val intss = List(List(1, 2, 3), List(4, 5), List(6))
scala> val f123456 = q"f(...$intss)"
f123456: universe.Tree = f(1, 2, 3)(4, 5)(6)
代码示例中lifting vs unquote拼接具体实现在哪里?
在两个示例中,两者同时发生。
Unquoting 是将 Tree
某处替换为另一个 Tree
结构的过程(如插值)。在此示例中,ints
不完全是 Tree
,但存在 Liftable[List[T]]
允许我们将 List[T]
取消引用到 Tree
,就好像它是一个 Tree
(即 Liftable
告诉编译器如何将此处的文字 List[Int]
转换为 Tree
以便它可以被替换)。
引用文档:
Unquote splicing is a way to unquote a variable number of elements.
在这里,可变数量的元素将是我们要取消引用的 List
中的元素。如果我们使用 q"f($ints)"
,那么我们将简单地取消引用 ints
作为 f
的单个参数。但也许我们想将重复的参数应用于 f
。为此,我们使用 unquote 拼接.
q"f(..$ints) // Using `..` means we get f(1, 2, 3) instead of f(List(1, 2, 3))
同样,文档说得最好,真的:
Dots near unquotee annotate degree of flattening and are also called splicing rank. ..$
expects argument to be an Iterable[Tree]
and ...$
expects Iterable[Iterable[Tree]]
.
所以 lifting 允许我们将 List[T]
取消引用到树 f(x)
中,就好像它是 Iterable[Tree]
和 unquote 拼接 允许我们取消引用 List[T]
包含的可变数量的元素作为 f
.
的多个参数
以下是不同的相关组合:
val listTree = q"scala.collection.immutable.List(1, 2, 3)"
val treeList = List(q"1", q"2", q"3")
val literalList = List(1, 2, 3)
scala> q"f($listTree)" // plain unquoting from another Tree
res6: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))
scala> q"f($literalList)" // unquoting from lifting
res7: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))
scala> q"f(..$treeList)" // plain unquote splicing
res8: reflect.runtime.universe.Tree = f(1, 2, 3)
scala> q"f(..$literalList)" // unquote splicing and lifting
res9: reflect.runtime.universe.Tree = f(1, 2, 3)
Quasiquotes 的 Scala 文档在解释时提到了这一点 Lifting:
One can also combine lifting and unquote splicing:
scala> val ints = List(1, 2, 3)
scala> val f123 = q"f(..$ints)"
f123: universe.Tree = f(1, 2, 3)
scala> val intss = List(List(1, 2, 3), List(4, 5), List(6))
scala> val f123456 = q"f(...$intss)"
f123456: universe.Tree = f(1, 2, 3)(4, 5)(6)
代码示例中lifting vs unquote拼接具体实现在哪里?
在两个示例中,两者同时发生。
Unquoting 是将 Tree
某处替换为另一个 Tree
结构的过程(如插值)。在此示例中,ints
不完全是 Tree
,但存在 Liftable[List[T]]
允许我们将 List[T]
取消引用到 Tree
,就好像它是一个 Tree
(即 Liftable
告诉编译器如何将此处的文字 List[Int]
转换为 Tree
以便它可以被替换)。
引用文档:
Unquote splicing is a way to unquote a variable number of elements.
在这里,可变数量的元素将是我们要取消引用的 List
中的元素。如果我们使用 q"f($ints)"
,那么我们将简单地取消引用 ints
作为 f
的单个参数。但也许我们想将重复的参数应用于 f
。为此,我们使用 unquote 拼接.
q"f(..$ints) // Using `..` means we get f(1, 2, 3) instead of f(List(1, 2, 3))
同样,文档说得最好,真的:
Dots near unquotee annotate degree of flattening and are also called splicing rank.
..$
expects argument to be anIterable[Tree]
and...$
expectsIterable[Iterable[Tree]]
.
所以 lifting 允许我们将 List[T]
取消引用到树 f(x)
中,就好像它是 Iterable[Tree]
和 unquote 拼接 允许我们取消引用 List[T]
包含的可变数量的元素作为 f
.
以下是不同的相关组合:
val listTree = q"scala.collection.immutable.List(1, 2, 3)"
val treeList = List(q"1", q"2", q"3")
val literalList = List(1, 2, 3)
scala> q"f($listTree)" // plain unquoting from another Tree
res6: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))
scala> q"f($literalList)" // unquoting from lifting
res7: reflect.runtime.universe.Tree = f(scala.collection.immutable.List(1, 2, 3))
scala> q"f(..$treeList)" // plain unquote splicing
res8: reflect.runtime.universe.Tree = f(1, 2, 3)
scala> q"f(..$literalList)" // unquote splicing and lifting
res9: reflect.runtime.universe.Tree = f(1, 2, 3)