Scala 3:查找具有给定注释的函数
Scala 3 : Finding functions with the given annotation
对于 Scala 3 宏,有谁知道找到具有给定注释的所有函数的方法吗?
例如:
@fruit
def apple(): Int = ???
@fruit
def banana(): Int = ???
@fruit
def coconut(): Int = ???
@fruit
def durian(): Int = ???
def elephant(): Int = ???
@fruit
def fig(): Int = ???
我想查找 apple, banana, coconut, durian, fig
的列表。它们可以在任何地方定义,但在我的例子中,它们都在一个包中。
此解决方案将从给定包中提取所有带有注释的定义。我还将利用 compile-time 反射。
此解决方案将从给定包中提取所有带有一些注释的定义。我还将利用 compile-time 反射。
所以,为了解决你的问题,我们需要把它分成:
- 从包中收集方法;
- 仅过滤具有给定注释的方法;
- 在函数应用中转换符号。
我想您可以将包和注释(以及 return 类型)作为类型参数传递。所以宏签名是这样的:
inline def findAllFunction[P, A <: ConstantAnnotation, R]: List[() => R] =
${Implementation.myMacroImpl[P, A, R]()}
第一点很简单。我们可以提取所有定义为的方法:
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
第二点也很简单。 Symbol
class 有可以在这种情况下使用的方法 hasAnnotation
:
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
最后一点有点挑战性。这里我们应该构造方法调用。所以我们需要创建对应于方法调用的 AST。受此 example 的启发,我们可以使用 Apply
调用定义。 Select
和 This
用于 select 将调用的正确方法:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
这里我使用了lamba调用,如果你想直接return这个值你应该改变最后两条指令:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => apply.asExprOf[R])
Expr.ofList(appliedDef)
综上所述,所有方法可以定义为:
def myMacroImpl[P: Type, A: Type, R: Type]()(using
Quotes
): Expr[List[() => R]] = {
import quotes.reflect.*
val annotation = TypeRepr.of[A].typeSymbol
val moduleTarget = TypeRepr.of[P].typeSymbol
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
def transformToFunctionApplication(
methods: List[Symbol]
): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
val methods = methodsFromPackage(moduleTarget)
val annotatedMethod = methodsAnnotatatedWith(methods, annotation)
transformToFunctionApplication(annotatedMethod)
}
最后,您可以将宏用作:
package org.tests
import org.tests.Macros.fruit
package foo {
@fruit
def check(): Int = 10
@fruit
def other(): Int = 11
}
@main def hello: Unit =
println("Hello world!")
println(Macros.findAllFunction[org.tests.foo, fruit, Int].map(_.apply())) /// List(10, 11)
对于 Scala 3 宏,有谁知道找到具有给定注释的所有函数的方法吗?
例如:
@fruit
def apple(): Int = ???
@fruit
def banana(): Int = ???
@fruit
def coconut(): Int = ???
@fruit
def durian(): Int = ???
def elephant(): Int = ???
@fruit
def fig(): Int = ???
我想查找 apple, banana, coconut, durian, fig
的列表。它们可以在任何地方定义,但在我的例子中,它们都在一个包中。
此解决方案将从给定包中提取所有带有注释的定义。我还将利用 compile-time 反射。
此解决方案将从给定包中提取所有带有一些注释的定义。我还将利用 compile-time 反射。 所以,为了解决你的问题,我们需要把它分成:
- 从包中收集方法;
- 仅过滤具有给定注释的方法;
- 在函数应用中转换符号。 我想您可以将包和注释(以及 return 类型)作为类型参数传递。所以宏签名是这样的:
inline def findAllFunction[P, A <: ConstantAnnotation, R]: List[() => R] =
${Implementation.myMacroImpl[P, A, R]()}
第一点很简单。我们可以提取所有定义为的方法:
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
第二点也很简单。 Symbol
class 有可以在这种情况下使用的方法 hasAnnotation
:
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
最后一点有点挑战性。这里我们应该构造方法调用。所以我们需要创建对应于方法调用的 AST。受此 example 的启发,我们可以使用 Apply
调用定义。 Select
和 This
用于 select 将调用的正确方法:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
这里我使用了lamba调用,如果你想直接return这个值你应该改变最后两条指令:
def transformToFunctionApplication(methods: List[Symbol]): Expr[List[R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => apply.asExprOf[R])
Expr.ofList(appliedDef)
综上所述,所有方法可以定义为:
def myMacroImpl[P: Type, A: Type, R: Type]()(using
Quotes
): Expr[List[() => R]] = {
import quotes.reflect.*
val annotation = TypeRepr.of[A].typeSymbol
val moduleTarget = TypeRepr.of[P].typeSymbol
def methodsFromPackage(packageSymbol: Symbol): List[Symbol] =
packageSymbol.declaredTypes
.filter(_.isClassDef)
.flatMap(_.declaredMethods)
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
def transformToFunctionApplication(
methods: List[Symbol]
): Expr[List[() => R]] =
val appliedDef = methods
.map(definition => Select(This(definition.owner), definition))
.map(select => Apply(select, List.empty))
.map(apply => '{ () => ${ apply.asExprOf[R] } })
Expr.ofList(appliedDef)
val methods = methodsFromPackage(moduleTarget)
val annotatedMethod = methodsAnnotatatedWith(methods, annotation)
transformToFunctionApplication(annotatedMethod)
}
最后,您可以将宏用作:
package org.tests
import org.tests.Macros.fruit
package foo {
@fruit
def check(): Int = 10
@fruit
def other(): Int = 11
}
@main def hello: Unit =
println("Hello world!")
println(Macros.findAllFunction[org.tests.foo, fruit, Int].map(_.apply())) /// List(10, 11)