【问题标题】:scala 3 macro: get class propertiesscala 3宏:获取类属性
【发布时间】:2022-09-30 08:27:20
【问题描述】:

我想编写一个宏来获取类的属性名称。 但不能在引用语句中使用Symbol 模块。我收到打击错误...

inline def getProps(inline className: String): Iterable[String] = ${ getPropsImpl(\'className) }
private def getPropsImpl(className: Expr[String])(using Quotes): Expr[Iterable[String]] = {
  import quotes.reflect.*

  val props = \'{
    Symbol.classSymbol($className).fieldMembers.map(_.name) // error access to parameter x$2 from 
  }                                                            wrong staging level:
  props                                                        - the definition is at level 0,
}                                                              - but the access is at level 1.
  • 而是将类作为类型参数传递
  • 但我需要处理类属性的Symbols。
  • 还有一个理由...
  • 在这个示例中,我只得到属性的名称,但我也想获得更多关于属性的信息,比如它的类型(propertySymbol.tree match ...,不能从Class[?] 对象中得到它(因为Class[?] 不包含输入参数)@cchantep

标签: scala metaprogramming scala-macros scala-3


【解决方案1】:

有宏的编译时间和运行时间。还有主要代码的编译时间和运行时间。宏的运行时间是主代码的编译时间。

def getPropsImpl... = 
  '{ Symbol.classSymbol($className).fieldMembers.map(_.name) }
  ...

是不正确的,因为 Scala 3 宏所做的是将树转换为树(即 Exprs 转换为 Exprs,Expr 是树的包装器)(*)。那个树

Symbol.classSymbol($className).fieldMembers.map(_.name)

在应用站点范围内将毫无意义。 SymbolSymbol.classSymbol 等在宏范围内有意义。

def getPropsImpl... = 
  Symbol.classSymbol(className).fieldMembers.map(_.name)
  ...

也是不正确的,因为className 作为一个值还不存在,它现在只是一棵树。

我想正确的是.valueOrAbort

import scala.quoted.*

inline def getProps(inline className: String): Iterable[String] = ${getPropsImpl('className)}

def getPropsImpl(className: Expr[String])(using Quotes): Expr[Iterable[String]] = {
  import quotes.reflect.*

  Expr.ofSeq(
    Symbol.classSymbol(className.valueOrAbort).fieldMembers.map(s =>
      Literal(StringConstant(s.name)).asExprOf[String]
    )
  )
}

用法:

// in other file
getProps("mypackage.App.A") //ArraySeq(s, i)

// in other subproject
package mypackage
object App {
  case class A(i: Int, s: String)
}

(*) Scala 2 宏可以用c.eval 做更多事情。在 Scala 3 中有类似的 thing staging.run 但它在宏中是 forbidden


实际上,c.eval(或禁止的staging.run)也可以在 Scala 3 中模拟

get annotations from class in scala 3 macros

【讨论】:

    猜你喜欢
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-01-02
    • 2022-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-02
    相关资源
    最近更新 更多