是否可以将抽象 class 或特征上的宏应用于所有子 classes?
Is it possible for a macro on an abstract class or trait to be applied to all subclasses?
说我在库中有一些特征(或抽象 class)Foo
,通常由用户代码扩展并且需要一些方法 numArgs
:
trait Foo {
// Number of arguments to the default constructor
def numArgs: Int
}
现在 numArgs
写起来很简单,但我想生成令人讨厌的样板。我可以用反射来做到这一点,但它很难看,而且不能移植到替代后端,如 ScalaJS、ScalaNative 或 GraalVM。
是否可以编写一个宏注释,我可以将 仅应用于Foo
(不需要它在每个subclass of Foo
) 以便生成方法?
没有。 abstract class(或 trait)上的宏注解只能更改此 class(trait)及其同伴 object 的 AST。您不能更改 parents、children、兄弟姐妹等。这样做是为了使宏注释在这个意义上是局部的。
此外,如果一个特征没有被密封,那么它的子class甚至在编译时都不知道。
如果class(trait)和subclass嵌套在一些object中,那么你可以注释object.
如果您想修改任意树,您可能需要编译器插件或通过 Scalameta 生成代码(生成源代码)。
我想在你的用例中你可以用 def macro 替换宏注释
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def numArgs[A]: Int = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val numArgs = weakTypeOf[A].typeSymbol.asClass.primaryConstructor.asMethod.paramLists.flatten.length
q"$numArgs"
}
class A(i: Int, s: String)
numArgs[A] // 2
或无形(如果子class是大小写class)
import shapeless.ops.hlist.Length
import shapeless.ops.nat.ToInt
import shapeless.{::, Generic, HList, HNil, Nat}
def numArgs[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList, N <: Nat]()(implicit gen: Generic.Aux[A, L], length: Length.Aux[L, N], toInt: ToInt[N]): Int = toInt()
}
case class A(i: Int, s: String)
numArgs[A]() // 2
说我在库中有一些特征(或抽象 class)Foo
,通常由用户代码扩展并且需要一些方法 numArgs
:
trait Foo {
// Number of arguments to the default constructor
def numArgs: Int
}
现在 numArgs
写起来很简单,但我想生成令人讨厌的样板。我可以用反射来做到这一点,但它很难看,而且不能移植到替代后端,如 ScalaJS、ScalaNative 或 GraalVM。
是否可以编写一个宏注释,我可以将 仅应用于Foo
(不需要它在每个subclass of Foo
) 以便生成方法?
没有。 abstract class(或 trait)上的宏注解只能更改此 class(trait)及其同伴 object 的 AST。您不能更改 parents、children、兄弟姐妹等。这样做是为了使宏注释在这个意义上是局部的。
此外,如果一个特征没有被密封,那么它的子class甚至在编译时都不知道。
如果class(trait)和subclass嵌套在一些object中,那么你可以注释object.
如果您想修改任意树,您可能需要编译器插件或通过 Scalameta 生成代码(生成源代码)。
我想在你的用例中你可以用 def macro 替换宏注释
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def numArgs[A]: Int = macro impl[A]
def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val numArgs = weakTypeOf[A].typeSymbol.asClass.primaryConstructor.asMethod.paramLists.flatten.length
q"$numArgs"
}
class A(i: Int, s: String)
numArgs[A] // 2
或无形(如果子class是大小写class)
import shapeless.ops.hlist.Length
import shapeless.ops.nat.ToInt
import shapeless.{::, Generic, HList, HNil, Nat}
def numArgs[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList, N <: Nat]()(implicit gen: Generic.Aux[A, L], length: Length.Aux[L, N], toInt: ToInt[N]): Int = toInt()
}
case class A(i: Int, s: String)
numArgs[A]() // 2