内容简介:本文的行文风格不求阅读意义上的可读性,而是期望读者能够跟着本文的一些探索,自己做一些尝试,即git clone本文涉及的代码阅读并实践。至于Scala元编程的一些介绍,请阅读 @王在祥 的《神奇的Scala Macro之旅系列》:一,我们从
本文的行文风格不求阅读意义上的可读性,而是期望读者能够跟着本文的一些探索,自己做一些尝试,即git clone本文涉及的代码阅读并实践。
至于Scala元编程的一些介绍,请阅读 @王在祥 的《神奇的Scala Macro之旅系列》:一, 二 , 三 , 四 。
绕不开的Sbt
我们从 Macro Paradise的例子 开始。有点遗憾的是,这个例子仍然在使用旧的Sbt。所以,我们的第一步是把构建的定义升级到当前Sbt的最新版。完整的项目见我fork的 sbt-example-paradise 。
首先,在project/build.properties中指定:
sbt.version=1.2.7 复制代码
然后,再修改build.sbt为:
val paradiseVersion = "2.1.0"
lazy val commonSettings = Seq(
scalaVersion := "2.12.8",
addCompilerPlugin("org.scalamacros" % "paradise" % paradiseVersion cross CrossVersion.full)
)
lazy val root = (project in file("."))
.aggregate(core, macros)
lazy val macros = (project in file("macros"))
.settings(commonSettings)
.settings(
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value
)
)
lazy val core = (project in file("core"))
.settings(commonSettings)
.dependsOn(macros)
复制代码
我们可以对比一下这一段SBT项目构建的定义和Maven的构建定义:
- commonSettings相当于Maven里面最顶层的pom.xml
- root相当于Maven中指定子模块的那几行
- macros和core分别对应两个子目录,其中,core依赖macros。
最后,运行一下这个例子:
$ sbt > project core # 切换到core子项目 > compile > run 复制代码
输出结果如下:
hello 复制代码
你好
@hello
object Test extends App {
println(this.hello)
}
复制代码
我们实际上运行的这段代码异常简洁。this指代Test这个独立对象(stand-alone object)本身,调用了一个不存在的方法hello。我们的问题是,@hello施放了什么样的魔法,生成了这样一个不存在的hello方法。
忽略别的语法细节,我们只看下面的这段代码:
annottees.map(_.tree).toList match {
case q"object $name extends ..$parents { ..$body }" :: Nil =>
q"""
object $name extends ..$parents {
def hello: ${typeOf[String]} = "hello"
..$body
}
"""
}
复制代码
从直观的感受,我们能猜想到, $name
即Test, $parents
即App, $body
就是代码的主体。parents和body前面有两个点,区别于name。
通过 $name
、 $parents
、 $body
这种特殊的语法形式,我们实际上把:
object Test extends App {
println(this.hello)
}
复制代码
变换成了:
object Test extends App {
println(this.hello)
def hello: String = "hello"
}
复制代码
尽管我们或许不知道其中的语法所对应的语义,更不清楚具体的实现机制,但这部分代码的可读性是非常棒(intuitive)的。
下一步?
现在大概知道了 @hello
所施放的黑魔法。下一步,我们就得弄明白这个简单的例子中,每一行代码的含义。
否则,任何拙劣的模仿和尝试,都是在浪费时间。
那我们应该如何学习这些黑魔法呢?官网的文档可读性并不好,而且不少是过时的。网络上也没有特别友好的面向新人的教程。
追本溯源,前面的项目实际上涉及到两个子项目,scala-reflect和paradise。在scala的源代码中,scala-reflect相关的代码单元测试并不多,所以我们从paradise的单元测试开始阅读。
git clone git@github.com:scalamacros/paradise.git 复制代码
可以将sbt的版本统一到1.2.7。这样做,主要为了防止去下载另外一个Sbt的版本,浪费大量时间。
很幸运,更改版本之后,项目可以正常编译,测试。
$ sbt > compile > project tests > test 复制代码
这个sbt的终端保持开启,然后用Intelli Idea打开整个项目,这样,应该能够更快地打开整个项目,我们在Sbt的会话中可以看到无端跳出来的日志:
[info] new client connected: network-1 复制代码
大致浏览一下这些单元测试的代码,可以获得一些初步的印象。
Macro Paradise将在Scala 2.13.x中内置
另外,这个 paradise插件
将在Scala 2.13.x中内置,所以我们还需要看一下Scala 2.13.x分支的代码。通过 git grep paradise
,可以看到一些蛛丝马迹。paradise的源代码主要被引入到了compiler和reflect下面,而单元测试则是在tests/macro-annot下面。
此时,我们可以将前面的sbt-example-paradise升级到Scala 2.13.x:
val paradiseVersion = "2.1.0"
lazy val commonSettings = Seq(
scalaVersion := "2.13.0-M5",
scalacOptions ++= Seq("-Ymacro-annotations")
)
lazy val root = (project in file("."))
.aggregate(core, macros)
lazy val macros = (project in file("macros"))
.settings(commonSettings)
.settings(
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value
)
)
lazy val core = (project in file("core"))
.settings(commonSettings)
.dependsOn(macros)
复制代码
为了避免构建定义太复杂,我们直接新开一个 分支 。
这里请注意一下编译选项 scalacOptions ++= Seq("-Ymacro-annotations")
。我是在Scala源代码中通过 git grep paradise
瞥见的这个编译选项,然后简单看了一下相关代码,了解到了其中的作用。这边第二次提及 git grep
,是因为在日常工作中,发现一些小伙伴不知道有 git grep
这么好用的工具,觉得十分诧异。
不过细想也很正常,很多时候,我们自己所认为的Common Sense,别人极有可能根本不了解。
所以,我们直接研究最新的2.13.x,不需要任何依赖,就可以探索Scala的元编程。
小结
本文从一个Macro Paradise项目的示例项目,从构建和代码阅读的细节入手,从大体上去感知Macro Paradise的某个具体的应用场景。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 编程范式 —— 函数式编程入门
- 【go网络编程】-HTTP编程
- 【go网络编程】-Socket编程
- c++并发编程—分布式编程
- Scala面向对象编程之Trait高级编程技术实践-JVM生态编程语言实战
- 函数式编程之数组的函数式编程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithms in Java
Robert Lafore / Sams / 2002-11-06 / USD 64.99
Data Structures and Algorithms in Java, Second Edition is designed to be easy to read and understand although the topic itself is complicated. Algorithms are the procedures that software programs use......一起来看看 《Data Structures and Algorithms in Java》 这本书的介绍吧!