MacroAnnotation
但它有很多警告。主要是“新定义在宏扩展之外是不可见的”。
https://github.com/lampepfl/dotty/tree/main/tests/run-macros中有很多示例(以
annot-
开头的)。其中一些示例在this answer中进行了演示。
这些似乎完全是黑盒(除了结构类型技巧)。他们真正能做的就是修改/覆盖现有定义。
我认为您可以通过使用 Macro 覆盖/包装定义来做同样的事情。
你可以用
MacroAnnotation
做什么,而你不能用宏来做?
你说得对,
@buildEnum
从 Scala 3 宏创建枚举
@genObj
, @modifyObj
来自How to generate a class in Dotty with macro?
@addClass
,@mainMacro
来自 Scala 3 中的Macro Annotations
@entity
来自How to generate parameterless constructor at compile time using scala 3 macro?
不是那么有趣,因为 新定义从 外部 宏扩展是不可见的。它们只是如何在 Scala 3 中编写宏注释的示例。为了使它们有趣,应该以某种方式使用新定义inside宏扩展。
但是看看
@memoize
和 @equals
来自 Macro Annotations in Scala 3。它们更有趣,因为新定义实际上是在 inside 宏扩展中使用的。所以有时宏注解在 Scala 3 中很有用。
尽管在 Scala 3 中,宏注释确实比 Scala 2 中的要严格得多(而且 Scala 3 中的宏通常比 Scala 2 中的宏更严格,例如没有c.eval
、c.parse
、准引号等)。因此,在宏或宏注释不够用的情况下,仍然需要使用 Scalameta(和 Semanticdb)、Scalafix、编译器插件等进行代码生成。您可以阅读 https://contributors.scala-lang.org/t/scala-3-macro-annotations-and-code-generation/6035 中的讨论,了解为什么要在 Scala 3 中引入宏注释。
我认为您可以通过使用 Macro 覆盖/包装定义来做同样的事情。
你可以用
做什么,而你不能用宏来做?MacroAnnotation
好吧,这就是你不需要在每次要检测另一个定义时都定义一个新的宏包装器的事情,用相同的宏注释对其进行注释就足够了。
此外,新定义在静态宏扩展之外是不可见的。它们存在于字节码中。您可以使用运行时反射来调用它们。例如对于
@mainMacro
来自Scala 3中的Macro Annotations
import Macros.mainMacro
import scala.annotation.experimental
@experimental
object App:
@mainMacro def Test(): Unit = println("macro generated main")
//scalac: List(class Test extends java.lang.Object {
// def main(args: scala.Array[scala.Predef.String]): scala.Unit = App.Test()
//}, @Macros.mainMacro def Test(): scala.Unit = scala.Predef.println("macro generated main"))
// new App.Test().main(Array[String]()) // doesn't compile: type Test is not a member of object App
val clazz = Class.forName("App$Test")
clazz.getMethod("main", classOf[Array[String]])
.invoke(clazz.newInstance(), Array[String]())
// macro generated main