Scala使用宏(而不是函数)的优势是什么?[已关闭]

vsnjm48y  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(150)

已关闭。这个问题是opinion-based。它目前不接受答案。
**想要改进这个问题吗?**更新问题,以便editing this post可以用事实和引用来回答它。

7年前就关闭了。
Improve this question
宏在Scala中用来做什么?宏可以做哪些不能用函数做的事情?
我想有一个好处是:
1.在调用点解析AST的能力,但这是相当罕见的用例。
1.代码不会导致额外的函数调用(直接修改AST),但现代编译器非常擅长内联函数。
我还遗漏了什么其他优势吗?

0ve6wy6x

0ve6wy6x1#

我同意Daenyth的观点,宏对代码生成有一些适度但有用的好处。
为了便于讨论,请考虑play-json在生成代码方面所能做的事情:
A)两个哑巴跑道:
1.以字符串形式读入Case类定义,然后写回
已更新的字符串
1.在“实际”运行中使用更新的定义。
起初,这非常简单,但却笨重且不是类型安全的
B)树和任务:将def作为字符串读取,但使用像Treehugger这样的运行时代码生成库将代码编写为树,并使用构建工具插件将代码生成任务添加到“编译”中
这给我们带来了一半的类型安全,而使用插件的顺序编译至少提供了一次运行的错觉。
C)宏:使用实验性功能在编译时读写树
宏是完全类型安全的,单次运行,让所有事情在一次编译中发生意味着很容易修改生成的代码

例如

假设我使用一个代码生成库,它将def printTypecase class Record(x: Int)相加,给出

case class Record(x: Int) {
  def printType = println("Int")
}

现在假设我想要将我自己的def goodbye也添加到类中:

  • 没有宏:*我可以

1)尝试将输出修改为

case class Record(x: Int) {
  def printType = println("Int")
  def goodbye = println("bye")
}

但随后我在输出文件的顶部遇到了打印的this is a generated file, DO NOT EDIT,提醒我该文件将被覆盖,因此我将不得不费力地关闭代码生成,或者
2)尝试修改Case类记录(x:int)的输入{def再见=println(“BYE”)},但是代码生成库可能看不到任意代码,因此我必须修改代码生成库本身。

  • 使用宏:*如果代码生成库依赖宏(并且库不显式地处理类体),我可以将新的def添加到输入中
case class Record(x: Int) {
  def goodbye = println("bye")
}

它很有效;我的def在那里,生成的def也在那里。

case class Record(x: Int) {
  def printType = println("Int")
  def goodbye = println("bye")
}
osh3o9ms

osh3o9ms2#

当宏从一开始就阻止您编写代码时,宏的优势就表现得最明显。
考虑一下play-json的情况。我可以定义一个case类,play-json格式化器宏可以创建方法,使用我在类上定义的字段在CC和json之间进行转换。
这里的关键是它获取了通常不在运行时表示的源代码的一部分(变量的名称),并且它确实在编译时表示(类型安全!)反射来创建特定的函数,而不是使用运行时(不安全)反射。

相关问题