【问题标题】:Scala macros, where are they used?Scala 宏,它们在哪里使用?
【发布时间】:2013-06-28 20:46:44
【问题描述】:
我刚刚注意到 Scala 有宏,但我从未见过任何使用它们的代码。它们似乎也与 C 预处理器宏等完全不同。通读overview 的宏,看起来它们提供的东西在Scala 中是不可能实现的。在动机标题下,有一个宏启用的列表:
- 语言虚拟化(重载/覆盖语义
支持深度嵌入 DSL 的原始编程语言),
- 程序具体化(为程序提供检查其
自己的代码),
- 自我优化(特定领域的自我应用
基于程序具体化的优化),
- 算法程序
构造(生成繁琐的代码
一种编程语言支持的抽象)。
在菜单的后面部分,有实验性的宏功能,例如类型宏、准引号、无类型宏等等。显然有这个需求!
对于那些构建非常复杂的库并对 Scala 有深入了解的人来说,所有这些似乎都是不错的功能。但是宏是否也为普通的 Scala 开发人员提供了一些东西?使用宏会让我的 Scala 代码更好吗?
【问题讨论】:
标签:
scala
macros
metaprogramming
template-meta-programming
【解决方案1】:
作为“普通”的 Scala 开发人员,您很可能不会自己编写宏,除非您有充分的理由。
宏是一种编译时元编程的方法,也就是说你编写程序。例如,一个 def-macro——它是 Scala 2.10 的一部分,尽管仍然是“实验性的”——看起来像一个常规方法,但无论何时你在代码中调用该方法,编译器都会用隐藏在该方法后面的任何宏替换该调用将产生(一个新的代码片段)。
一个非常简单的例子。将您的项目编译到代码中的日期:
import java.util.Date
import reflect.macros.Context
import language.experimental.macros
object CompileTime {
def apply(): Date = macro applyImpl
def applyImpl(c: Context)(): c.Expr[Date] = {
import c.universe._
val now = System.currentTimeMillis() // this is executed during compilation!
val nowExpr = c.Expr[Long](Literal(Constant(now)))
val code = reify(new Date(nowExpr.splice))
c.Expr(code.tree)
}
}
使用该宏(以下代码必须与上面的宏代码分开编译):
object MacroTest extends App {
println(s"This project was compiled on ${CompileTime()}")
}
(如果你多次运行,你会发现编译时间确实是恒定的)
简而言之,宏提供的功能在任何以前的 Scala 版本中不可用。你可以用宏来做你不能做的事情(通常你可以使用运行时反射来编写类似的东西,但是宏在编译时会被检查)。
但是,作为用户,您将越来越多地接触到包含宏的库,因为它们可以提供完全类型安全的强大构造。例如,可以使用宏来实现案例类中 JSON 的自动序列化器,因为宏可以检查案例类的类型并构建正确的程序结构 (AST) 来读取和写入该案例类,而不存在运行时的危险失败。
一些随机链接