首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用scala 3反射查找所有包级对象

使用scala 3反射查找所有包级对象
EN

Stack Overflow用户
提问于 2021-10-25 23:08:58
回答 1查看 125关注 0票数 2

我正在尝试获取与所有包级对象相对应的ExprAny列表。我可以找到包符号本身(通过追赶任何顶级对象的符号所有者),然后遍历declaredFields。我可以以这种方式找到顶级对象ValDef节点,但是在ValDef中没有关联的术语。我也不能在包树上使用Term.select来获取声明的成员,因为我无法获得包符号的树。

似乎应该可以从这些顶级单例对象的符号中得到与这些顶级单例对象相关联的术语(而不仅仅是ValDef),但我无法理解。

基本上我想做这样的事情:

代码语言:javascript
复制
inline def packageToucher[T](something : T) : List[Any] = {
    ${ packageToucherImpl('something) } 
}

def packageToucherImpl[T](something : Expr[T])(using Quotes, Type[T]): Expr[List[Any]] = {
    import quotes.reflect.*
    // assume something is a top level object
    val _package = TypeRepr.of[T].typeSymbol.owner 
    val fields = _package.declaredFields
    val packageExpr = _package.tree.asExpr //  assertion failed: Cannot get tree of package symbol
    val packageTree = packageExpr.asTerm
    val fieldExprs : List[Expr[Any]] = fields.map( f => packageTree.select(f).asExpr)

    Expr.ofList(fieldExprs)
}

使用的一个例子是:

代码语言:javascript
复制
// in actions.scala
package potato

object Actions // dummy object for finding package

object yelling extends Action("yell")

object sleeping extends Action("sleep")

object typing extends Action("type")

主要是:

代码语言:javascript
复制
import potato.*
val actions = Macros.packageToucher(Actions) // should be List(Actions, yelling, sleeping, typing)

任何帮助都将不胜感激。对于scala 3宏,我是个菜鸟。

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-25 10:27:36

嗯,经过大量的努力,尝试,和错误:我已经找到了解决办法。也许这对其他人是有用的。

代码语言:javascript
复制
  inline def packageToucher[T](something : T) : List[Any] = {
    ${ packageToucherImpl('something) }
  }

  @experimental // needed for access to Symbol.termRef
  def packageToucherImpl[T](something : Expr[T])(using Quotes, Type[T]): Expr[List[Any]] = {
    import quotes.reflect.*
    // assume something is a top level object
    val _package = TypeRepr.of[T].typeSymbol.owner

    val fields = _package.fieldMembers

    // for some reason, scala generates erased companion objects for Classes that don't have them.
    // Luckily they can be filtered out by checking for the synthetic flag
    val valdefs = fields.filter(f => f.isValDef && !f.flags.is(Flags.Synthetic))

    // here's where the magic happens, we can't access the package's companion object tree directly
    // but we can construct one using AST nodes
    val packageTerm = Ident(_package.companionModule.termRef)
    val exprs = valdefs.map(Select(packageTerm, _).asExpr)

    Expr.ofList(exprs)
  }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69715707

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档