作为一个“普通”的 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) 来读取和写入该案例类,而不存在运行时的危险失败。
一些随机链接