Scala 3 反射:收集所有单例对象的成员

问题描述 投票:0回答:1

我在 Scala 2 中有一个使用反射的方法。它在 Scala 3 中不起作用,我想重新实现它,以便它适用于 Scala 3。(我不再需要它用于 Scala 2,所以它不需要同时适用于 both)。

该方法的目的是检查一个对象并按照声明的顺序收集其作为成员的单例对象的任何实例。 (程序员提前知道所有此类单例对象都会扩展

A
)。

工作正常。

def allSingletonObjects[A](host: Any): Vector[A] = {
 import scala.reflect.runtime.universe.runtimeMirror
 val mirror = runtimeMirror(host.getClass.getClassLoader)

 mirror
   .classSymbol(host.getClass)
   .info
   .members
   .filter(_.isModule)
   .map(sym => mirror.reflectModule(sym.asModule).instance.asInstanceOf[A])
   .toVector
   .reverse
}

这是一个如何使用它的示例。

sealed trait Color

object Color {
  case object Red extends Color
  
  case object Green extends Color
  
  case object Blue extends Color
}

在此示例中,

allSingletonObjects[Color](Color)
将返回
Vector(Color.Red, Color.Green, Color.Blue)

如何在 Scala 3 中实现

allSingletonObjects

注意:我无法更改类型建模的方式(例如使用枚举)。理想情况下,我希望

allSingletonObjects
能够像 Scala 2 中那样工作。

scala reflection scala-3
1个回答
0
投票

我同意这些评论,你可能应该找到更好的方法来做到这一点,但这是一个工作版本:

import scala.quoted.*

inline def allSingletonObjects[A](host: Any) = allSingletonObjectsSeq[A](host).toVector
inline def allSingletonObjectsSeq[A](host: Any) = ${allSingletonObjectsSeqImpl[A]('host)}

def allSingletonObjectsSeqImpl[A: Type](host: Expr[Any])(using quotes: Quotes): Expr[Seq[A]] =
  import quotes.reflect.*
  
  Expr.ofSeq:
    host
      .asTerm
      .tpe
      .classSymbol
      .get
      .declarations
      .filter(sym => sym.flags.is(Flags.Case | Flags.Final | Flags.Lazy | Flags.Module | Flags.StableRealizable))
      .map(sym => Ref(sym).asExprOf[A])
© www.soinside.com 2019 - 2024. All rights reserved.