gpt4 book ai didi

斯卡拉 3 : Finding functions with the given annotation

转载 作者:行者123 更新时间:2023-12-05 02:32:59 24 4
gpt4 key购买 nike

对于 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 的列表。它们可以在任何地方定义,但在我的例子中,它们都在一个包中。

最佳答案

此解决方案将从给定包中提取所有带有注释的定义。我还将利用编译时反射。

此解决方案将从给定包中提取所有带有一些注释的定义。我还将利用编译时反射。因此,为了解决您的问题,我们需要将其分为:

  • 从包中收集方法;
  • 仅过滤具有给定注解的方法;
  • 在函数应用中转换符号。我想您可以将包和注释(以及返回类型)作为类型参数传递。所以宏签名是这样的:
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。受此启发 example ,我们可以使用 Apply 调用定义。 SelectThis 用于选择将被调用的正确方法:

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)

Scastie

关于斯卡拉 3 : Finding functions with the given annotation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71068893/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com