Scala宏,它们在哪里使用?

时间:2013-07-01 16:34:04

标签: scala macros metaprogramming template-meta-programming

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

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

稍后在菜单中,有实验宏功能,例如类型宏,quasiquotes,无类型宏甚至更多。显然需要这个!

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

1 个答案:

答案 0 :(得分:20)

作为“普通”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)来读取和写入案例类,而不会有运行时的危险故障。

一些随机链接