Quasiquotes are a neat notation that lets you manipulate Scala syntax trees with ease:

scala> val tree = q"i am { a quasiquote }"
tree: universe.Tree = i.am(a.quasiquote)

Every time you wrap a snippet of code in q"..." it will become a tree that represents a given snippet. As you might have already noticed, quotation syntax is just another usage of extensible string interpolation, introduced in 2.10. Although they look like strings they operate on syntactic trees under the hood.

The same syntax can be used to match trees as patterns:

scala> println(tree match { case q"i am { a quasiquote }" => "it worked!" })
it worked!

Whenever you match a tree with a quasiquote it will match whenever the structureof a given tree is equivalent to the one you've provided as a pattern. You can check for structural equality manually with the help of equalsStructure method:

scala> println(q"foo + bar" equalsStructure q"foo.+(bar)")
true

You can also put things into quasiquotation with the help of $:

scala> val aquasiquote = q"a quasiquote"
aquasiquote: universe.Select = a.quasiquote scala> val tree = q"i am { $aquasiquote }"
tree: universe.Tree = i.am(a.quasiquote)

This operation is also known as unquoting. Whenever you unquote an expression of type Tree in a quasiquote it will structurally substitute that tree into that location. Most of the time such substitutions between quotes is equivalent to a textual substitution of the source code.

Similarly, one can structurally deconstruct a tree using unquoting in pattern matching:

scala> val q"i am $what" = q"i am { a quasiquote }"
what: universe.Tree = a.quasiquote

Interpolators

Scala is a language with rich syntax that differs greatly depending on the syntactical context:

scala> val x = q"""
val x: List[Int] = List(1, 2) match {
case List(a, b) => List(a + b)
}
"""
x: universe.ValDef =
val x: List[Int] = List(1, 2) match {
case List((a @ _), (b @ _)) => List(a.$plus(b))
}

In this example we see three primary contexts being used:

  1. List(1, 2) and List(a + b) are expressions
  2. List[Int] is a type
  3. List(a, b) is a pattern

Each of these contexts is covered by a separate interpolator:

  Used for
q expressions, definitions and imports
tq types
pq patterns

Syntactical similarity between different contexts doesn't imply similarity between underlying trees:

scala> println(q"List[Int]" equalsStructure tq"List[Int]")
false

If we peek under the hood we’ll see that trees are, indeed different:

scala> println(showRaw(q"List[Int]"))
TypeApply(Ident(TermName("List")), List(Ident(TypeName("Int")))) scala> println(showRaw(tq"List[Int]"))
AppliedTypeTree(Ident(TypeName("List")), List(Ident(TypeName("Int"))))

Similarly, patterns and expressions are also not equivalent:

scala> println(pq"List(a, b)" equalsStructure q"List(a, b)")
false

It’s extremely important to use the right interpolator for the job in order to construct a valid syntax tree.

Additionally there are two auxiliary interpolators that let you work with minor areas of scala syntax:

  Used for
cq case clause
fq for loop enumerator

See the section syntax summary for details.

Splicing

Unquote splicing is a way to unquote a variable number of elements:

scala> val ab = List(q"a", q"b")
scala> val fab = q"f(..$ab)"
fab: universe.Tree = f(a, b)

Dots before the unquotee annotate indicate a degree of flattenning and are called a splicing rank. ..$ expects the argument to be an Iterable[Tree] and ...$ expects an Iterable[Iterable[Tree]].

Splicing can easily be combined with regular unquotation:

scala> val c = q"c"
scala> val fabc = q"f(..$ab, $c)"
fabc: universe.Tree = f(a, b, c) scala> val fcab = q"f($c, ..$ab)"
fcab: universe.Tree = f(c, a, b) scala> val fabcab = q"f(..$ab, $c, ..$ab)"
fabcab: universe.Tree = f(a, b, c, a, b)

If you want to abstract over applications even further, you can use ...$:

scala> val argss = List(ab, List(c))
arglists: List[List[universe.Ident]] = List(List(a, b), List(c)) scala> val fargss = q"f(...$argss)"
fargss: universe.Tree = f(a, b)(c)

At the moment ...$ splicing is only supported for function applications and parameter lists in def and class definitions.

Similarly to construction one can also use ..$ and ...$ to tear trees apart:

scala> val q"f(..$args)" = q"f(a, b)"
args: List[universe.Tree] = List(a, b) scala> val q"f(...$argss)" = q"f(a, b)(c)"
argss: List[List[universe.Tree]] = List(List(a, b), List(c))

There are some limitations in the way you can combine splicing with regular $variable extraction:

case q"f($first, ..$rest)" => // ok
case q"f(..$init, $last)" => // ok
case q"f(..$a, ..$b)" => // not allowed

So, in general, only one ..$ is allowed per given list. Similar restrictions also apply to ...$:

case q"f(..$first)(...$rest)" => // ok
case q"f(...$init)(..$first)" => // ok
case q"f(...$a)(...$b)" => // not allowed

In this section we only worked with function arguments but the same splicing rules are true for all syntax forms with a variable number of elements. Syntax summaryand the corresponding details sections demonstrate how you can use splicing with other syntactic forms.

Scala 准引用 - Quasiquote介绍的更多相关文章

  1. Scala进阶之路-Scala中的泛型介绍

    Scala进阶之路-Scala中的泛型介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型.我们不可能一一列举所有的参数类 ...

  2. 基于OGG的Oracle与Hadoop集群准实时同步介绍

    版权声明:本文由王亮原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/220 来源:腾云阁 https://www.qclou ...

  3. Python学习四|变量、对象、引用的介绍

    变量 变量创建:一个变量也就是变量名,就像a,当代码第一次赋值时就创建了它.之后的赋值将会改变已创建的变量名的值,从技术上讲,Python在代码运行之前先检测变量名,可以当成是最初的赋值创建了变量. ...

  4. 01_Java 软、弱引用语法介绍

    文章导读: 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用, 本章内容介绍了Reference的概 ...

  5. 对C++11中的`移动语义`与`右值引用`的介绍与讨论

    本文主要介绍了C++11中的移动语义与右值引用, 并且对其中的一些坑做了深入的讨论. 在正式介绍这部分内容之前, 我们先介绍一下rule of three/five原则, 与copy-and-swap ...

  6. jdb调试scala代码的简单介绍

    在linux调试C/C++的代码需要通过gdb,调试java代码呢?那就需要用到jdb工具了.关于jdb的用法在网上大家都可以找到相应的文章,但是对scala进行调试的就比较少了.其实调试的大致流程都 ...

  7. 第4节 Scala中的actor介绍:1、actor概念介绍;2、actor执行顺序和发送消息的方式

    10.    Scala Actor并发编程 10.1.   课程目标 10.1.1.    目标一:熟悉Scala Actor并发编程 10.1.2.    目标二:为学习Akka做准备 注:Sca ...

  8. 神奇的Scala Macro之旅(三)- 实际应用

    在上一篇中,我们示范了使用macro来重写 Log 的 debug/info 方法,并大致的介绍了 macro 的基本语法.基本使用方法.以及macro背后的一些概念, 如AST等.那么,本篇中,我们 ...

  9. Java 四种引用介绍及使用场景

    强引用-FinalReference 介绍: 强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收,使用方式: String str = new String("s ...

随机推荐

  1. python随机选取目录下的若干个文件

    个人记录用. python模块random argparse shutil import argparse parser = argparse.ArgumentParser() parser.add_ ...

  2. 锁定文件失败,打不开磁盘“D:\biehl\centos\taotao\taotao-dubbo-register\CentOS-000001.vmdk”或它所依赖的某个快照磁盘。模块“Disk”启动失败。未能启动虚拟机

    1.锁定文件失败,打不开磁盘“D:\biehl\centos\taotao\taotao-dubbo-register\CentOS-000001.vmdk”或它所依赖的某个快照磁盘.模块“Disk” ...

  3. Winform中设置ZedGraph的曲线为散点图

    场景 Winform中设置ZedGraph的曲线符号Symbol以及对应关系: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...

  4. SATA、PCIe、AHCI、NVMe

    IT 界总喜欢发明新名词.而且同一个东西,可能有几个不同的名字.同一个名字,又可能指不同的东西. 从物理接口角度来说,我们常见的有IDE(淘汰),SATA,PCIe,M.2(固态硬盘) M.2插槽是有 ...

  5. Scrapy 运行多个爬虫

    本文所使用的 Scrapy 版本:Scrapy==1.8.0 一个 Scrapy 项目下可能会有多个爬虫,本文陈述两种情况: 多个爬虫 所有爬虫 显然,这两种情况并不一定是等同的.假设当前项目下有 3 ...

  6. 【转】Python学习---超详细字符串用法大全,好文推荐!

    来自:Python编程与实战(微信号:pthon1024),作者:Jerryning 没有办法转,整个复制下来了 本文要点 字符串拼接 拆分含有多种分隔符的字符串 判读字符串a是否以字符串b开头或结尾 ...

  7. Android中设置状态栏颜色和字体颜色

    1.在这里设置的状态栏背景为白色,字体为暗色 创建一个方法进行设置: protected void setStatusBar() { if (Build.VERSION.SDK_INT >= B ...

  8. LeeCode——Combine Two Tables

    Table: Person +-------------+---------+ | Column Name | Type | +-------------+---------+ | PersonId ...

  9. [20190505]关于latch 一些统计信息.txt

    [20190505]关于latch 一些统计信息.txt --//我在两篇文章,提到一些latch的统计信息.链接如下:http://blog.itpub.net/267265/viewspace-2 ...

  10. Django 简单评论实现

    创建项目 django_comment 和应用 app01 修改 urls.py 文件 from django.contrib import admin from django.urls import ...