简体   繁体   English

如何在Scala中使用反射获取所有对象值和子对象值?

[英]How can I get all object vals and subobject vals using reflection in Scala?

I have an object that looks like this: 我有一个看起来像这样的对象:

object Settings {
  final val Host = "host"
  final val Protocol = "protocol"

  object User {
    final val Name = "username"
    final val Password = "password"
  }

  object Subject {
    final val Query = "query"
    final val Predicate = "predicate"
  }
}

What I'd like to do is something like membersAsHash(classOf[CollectionSettings]) and receive a hash) of all of the vals that I've declared in the object: 我想做的是像membersAsHash(classOf[CollectionSettings])并接收我在对象中声明的所有val的哈希值:

[
  Host => "host", 
  Protocol => "protocol", 
  Name => "username",
  Password => "password",
  Query => "query",
  Predicate => "predicate"
]

It'd be fine if the key was a string, even the full package name (eg com.example.Settings.User). 如果键是一个字符串,即使是完整的包名称(例如com.example.Settings.User),也没关系。 What I really need is the values, so if I can only get that, it's still acceptable. 我真正需要的是价值观,所以如果我只能得到它,它仍然是可以接受的。

This has gotten me the name of the subobjects, but I can't seem to figure out how to get the vals that are internal to each: 这让我得到了子对象的名字,但我似乎无法弄清楚如何获得每个子对象的内部值:

val optionsToCheck = {
  import scala.reflect.runtime.{universe => ru}
  val mirror = ru.runtimeMirror(getClass.getClassLoader)
  val subObjects = ru.typeOf[CollectionSettings.type].declarations.filter(_.isModule)
  subobjects.map(o => mirror.reflectModule(o.asModule).instance.asInstanceOf[Object].toString).toList
}

The neat thing here is that you're using constant value definitions (ie, final values with no type annotation; see §4.1 of the language specification ), so you don't even need any mirrors: 这里的好处是你使用常量值定义 (即没有类型注释的最终值;参见语言规范的 §4.1),所以你甚至不需要任何镜像:

def deepMembers[A: scala.reflect.runtime.universe.TypeTag](a: A) = {
  import scala.reflect.runtime.universe._

  def members(s: Symbol): Map[String, String] =
    s.typeSignature.declarations.collect {
      case m: ModuleSymbol => members(m)
      case m: MethodSymbol if m.isAccessor => m.returnType match {
        case ConstantType(Constant(s: String)) => Map(m.name.decoded -> s)
        case _ => Map.empty[String, String]
      }
    }.foldLeft(Map.empty[String, String])(_ ++ _)

  members(typeOf[A].termSymbol)
}

It works like this: 它的工作原理如下:

scala> deepMembers(Settings) foreach println
(Name,username)
(Predicate,predicate)
(Query,query)
(Password,password)
(Protocol,protocol)
(Host,host)

If for some reason you couldn't use constant value definitions, you'd need to adjust the MethodSymbol case to work with instance mirrors, but the basic approach to recursively collecting key-value pairs from child objects would be the same. 如果由于某种原因您无法使用常量值定义,则需要调整MethodSymbol案例以使用实例镜像,但从子对象递归收集键值对的基本方法将是相同的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM