15

我刚刚注意到 Scala 有宏,但我从未见过任何使用它们的代码。它们似乎也与 C 预处理器宏等完全不同。通读宏的概述,看起来它们并没有提供以前在 Scala 中不可能提供的任何东西。在动机标题下,有一个宏启用的列表:

  • 语言虚拟化(重载/覆盖原始编程语言的语义以实现 DSL 的深度嵌入),
  • 程序具体化(为程序提供检查自己代码的方法),
  • 自我优化(基于程序具体化的特定领域优化的自我应用),
  • 算法程序构造(使用编程语言支持的抽象来生成繁琐的代码)。

稍后在菜单中,有实验性的宏功能,例如类型宏、准引号、无类型宏等等。显然有这个需求!

对于那些构建非常复杂的库并对 Scala 有深入了解的人来说,所有这些似乎都是不错的功能。但是宏是否也为普通的 Scala 开发人员提供了一些东西?使用宏会让我的 Scala 代码更好吗?

4

1 回答 1

26

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

一些随机链接

于 2013-07-01T17:16:34.463 回答