已关闭。这个问题是opinion-based。它目前不接受答案。
**想要改进这个问题吗?**更新问题,以便editing this post可以用事实和引用来回答它。
7年前就关闭了。
Improve this question
宏在Scala中用来做什么?宏可以做哪些不能用函数做的事情?
我想有一个好处是:
1.在调用点解析AST的能力,但这是相当罕见的用例。
1.代码不会导致额外的函数调用(直接修改AST),但现代编译器非常擅长内联函数。
我还遗漏了什么其他优势吗?
已关闭。这个问题是opinion-based。它目前不接受答案。
**想要改进这个问题吗?**更新问题,以便editing this post可以用事实和引用来回答它。
7年前就关闭了。
Improve this question
宏在Scala中用来做什么?宏可以做哪些不能用函数做的事情?
我想有一个好处是:
1.在调用点解析AST的能力,但这是相当罕见的用例。
1.代码不会导致额外的函数调用(直接修改AST),但现代编译器非常擅长内联函数。
我还遗漏了什么其他优势吗?
2条答案
按热度按时间0ve6wy6x1#
我同意Daenyth的观点,宏对代码生成有一些适度但有用的好处。
为了便于讨论,请考虑play-json在生成代码方面所能做的事情:
A)两个哑巴跑道:
1.以字符串形式读入Case类定义,然后写回
已更新的字符串
1.在“实际”运行中使用更新的定义。
起初,这非常简单,但却笨重且不是类型安全的
B)树和任务:将def作为字符串读取,但使用像Treehugger这样的运行时代码生成库将代码编写为树,并使用构建工具插件将代码生成任务添加到“编译”中
这给我们带来了一半的类型安全,而使用插件的顺序编译至少提供了一次运行的错觉。
C)宏:使用实验性功能在编译时读写树
宏是完全类型安全的,单次运行,让所有事情在一次编译中发生意味着很容易修改生成的代码。
例如
假设我使用一个代码生成库,它将
def printType
与case class Record(x: Int)
相加,给出现在假设我想要将我自己的
def goodbye
也添加到类中:1)尝试将输出修改为
但随后我在输出文件的顶部遇到了打印的
this is a generated file, DO NOT EDIT
,提醒我该文件将被覆盖,因此我将不得不费力地关闭代码生成,或者2)尝试修改Case类记录(x:int)的输入{def再见=println(“BYE”)},但是代码生成库可能看不到任意代码,因此我必须修改代码生成库本身。
它很有效;我的def在那里,生成的def也在那里。
osh3o9ms2#
当宏从一开始就阻止您编写代码时,宏的优势就表现得最明显。
考虑一下play-json的情况。我可以定义一个case类,play-json格式化器宏可以创建方法,使用我在类上定义的字段在CC和json之间进行转换。
这里的关键是它获取了通常不在运行时表示的源代码的一部分(变量的名称),并且它确实在编译时表示(类型安全!)反射来创建特定的函数,而不是使用运行时(不安全)反射。