gpt4 book ai didi

scala - 从 Scala 宏中按名称访问类定义

转载 作者:行者123 更新时间:2023-12-03 21:31:18 26 4
gpt4 key购买 nike

我正在尝试创建一个 Scala 宏,它定义了一个 Class 参数,并根据作为参数提供的 Class 的实现来修改它所附加的类。

//Simple class with a few arguments
class A(a: String, b: String)

//Definition of this class should be modified based on class definition of A
@parameterized(classOf[A])
class B

我设法创建了一个简单的宏,它能够从注释中提取参数,从而生成一个包含完整类名的字符串表示形式的 TypeName 对象。

现在的问题是我需要从宏实现中访问 A 的定义(具体来说,我想看看构造函数参数是什么)。

有没有办法以某种方式访问​​/创建 TypeTag[A]?有没有办法访问A类的AST?

为了说明我想要实现的目标,这是我目前拥有的宏定义:
object parameterizedMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
import Flag._

//Extract the parameter type which was provided as an argument (rather hacky way of getting this info)
val parameterType = c.macroApplication match {
case Apply(Select(Apply(_, List(
TypeApply(Ident(TermName("classOf")), List(Ident(TypeName(parameterType))))
)) , _), _) => parameterType
case _ =>
sys.error("Could not match @parameterized arguments. Was a class provided?")
}

//Should generate method list based on the code of parameterType
val methods = ???

val result = {
annottees.map(_.tree).toList match {
case q"object $name extends ..$parents { ..$body }" :: Nil =>
q"""
object $name extends ..$parents {
..${methods}
..$body
}
"""
case q"class $name (..$args) extends ..$parents { ..$body }" :: Nil =>
q"""
class $name (..$args) extends ..$parents {
..${methods}
..$body
}
"""
}
}

c.Expr[Any](result)
}
}

最佳答案

这需要大量的反复试验,因为我没有设法找到关于各种类的大量文档,但我最终设法实现了我想做的事情。

为了获取参数,我最终不得不将完全限定的名称而不是原始的 TypeOf[Name] 放在注释中。 .

@parameterized(the.fully.qualified.Name)

然后我可以使用
val parameterType = c.macroApplication match {
case Apply(Select(Apply(_, List(
parameterType
)) , _), _) => parameterType
case _ =>
error("Could not match @parameterized arguments. Was a class provided?")
}
val fullClassName = parameterType.toString()

使用 TypeOf正如原始帖子中提到的那样对我不起作用,因为我没有设法从 TypeApply 获得到正确的完全限定名称。这并没有真正使整个事情变得不安全,因为一切都在编译时检查,但它看起来确实有点不像标准 Scala。

一旦我有了完全限定的名称,我就可以使用宇宙的镜像 ( The documentation on mirrors helped here ) 来获取 ClassSymbol,从中可以获取类构造函数参数:
val constructorArguments = {
val clazz = c.mirror.staticClass(fullClassName) //Get ClassSymbol
val clazzInfo = clazz.info //Turn ClassSymbol into Type
val constructor = clazzInfo.member(termNames.CONSTRUCTOR) //Get constructor member Symbol
val constructorMethod = constructor.asMethod //Turn into MethodSymbol
val parametersList = constructorMethod.paramLists //Finally extract list of parameters

if (parametersList.size != 1)
error("Expected only a single constructor in " + fullClassName)

val parameters = parametersList.head

for (parameter <- parameters) yield {
val term = parameter.asTerm //parameter is a term
(term.name.toString, term.typeSignature)
}
}

关于scala - 从 Scala 宏中按名称访问类定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36333798/

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