對于 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。它們可以在任何地方定義,但在我的情況下,它們都將在一個包中。
uj5u.com熱心網友回復:
此解決方案將從給定包中提取帶有一些注釋的所有定義。我還將利用編譯時反射。
此解決方案將從給定包中提取所有帶有一些注釋的定義。我還將利用編譯時反射。因此,要解決您的問題,我們需要將其分為:
- 從包中收集的方法;
- 僅過濾具有給定注釋的方法;
- 在函式應用程式中轉換符號。我想您可以將包和注釋(以及回傳型別)作為型別引數傳遞。所以宏簽名是這樣的:
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類具有hasAnnotation可以在這種情況下使用的方法:
def methodsAnnotatatedWith(
methods: List[Symbol],
annotation: Symbol
): List[Symbol] =
methods.filter(_.hasAnnotation(annotation))
最后一點有點挑戰性。這里我們應該構造方法呼叫。所以我們需要創建對應方法呼叫的AST。受這個例子的啟發,我們可以使用Apply. Select并This用于選擇將被呼叫的正確方法:
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呼叫,如果你想直接回傳值你應該改變最后兩條指令:
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)
斯卡斯蒂
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/424399.html
上一篇:SparkScala-如何一起使用$"col"和S字串插值?
下一篇:Akka型別的Actor單元測驗
