Отражение Scala 2.10, как извлечь значения полей из класса case, т.е. список полей из класса case

Как я могу извлечь значения полей из класса case в scala, используя новую модель отражения в scala 2.10? Например, использование приведенных ниже методов не извлекает методы поля.

  def getMethods[T:TypeTag](t:T) =  typeOf[T].members.collect {
    case m:MethodSymbol => m
  }

Я планирую закачать их в

  for {field <- fields} {
    currentMirror.reflect(caseClass).reflectField(field).get
  }

person J Pullar    schedule 18.04.2013    source источник


Ответы (2)


MethodSymbol имеет метод isCaseAccessor который позволяет вам сделать именно это:

def getMethods[T: TypeTag] = typeOf[T].members.collect {
  case m: MethodSymbol if m.isCaseAccessor => m
}.toList

Теперь вы можете написать следующее:

scala> case class Person(name: String, age: Int)
defined class Person

scala> getMethods[Person]
res1: List[reflect.runtime.universe.MethodSymbol] = List(value age, value name)

И вы получаете только те символы метода, которые вам нужны.

Если вам просто нужно фактическое имя поля (а не префикс value) и вы хотите, чтобы они были в том же порядке, то:

def getMethods[T: TypeTag]: List[String] =
  typeOf[T].members.sorted.collect {
    case m: MethodSymbol if m.isCaseAccessor => m.name.toString
  }
person Travis Brown    schedule 18.04.2013
comment
Ах, теперь я понимаю, что мой подход был неправильным. Любая идея, как получить caseAccessors из неизвестного класса case? IE тот, который в настоящее время хранится как val SomeCaseClass: Any - person J Pullar; 18.04.2013
comment
Подождите, не понял currentMirror.reflect(someCaseClass).symbol.asType.typeSignature.members - person J Pullar; 18.04.2013
comment
Может ли это работать с многопоточной средой в scala 2.10? - person jilen; 12.04.2014
comment
Любой способ заставить это возвращать методы в том же порядке, в котором они были объявлены ?? - person samthebest; 03.10.2014
comment
@samthebest: Да! Просто добавьте .sorted после members (см. подробности в MemberScope документах). - person Travis Brown; 03.10.2014
comment
Было бы удобно быть непосредственно частью case classes - person WestCoastProjects; 21.07.2019
comment
Я не могу скомпилировать это из-за того, что Symbols является Trait, поэтому его компоненты, особенно MethodSymbol, не могут быть импортированы. Можете ли вы расширить пример, включив в него импорт Symbols и MethodSymbol? - person WestCoastProjects; 21.07.2019
comment
@javadba Это ответ шестилетней давности, и я не очень заинтересован в его обновлении сам, но не стесняйтесь редактировать - вероятно, ему просто нужен импорт scala.reflect.runtime.universe._ . - person Travis Brown; 23.07.2019

Если вы хотите поизобретать, вы можете расположить их по порядку, проверив символ конструктора. Этот код работает, даже если рассматриваемый тип класса case имеет несколько определенных конструкторов.

  import scala.collection.immutable.ListMap
  import scala.reflect.runtime.universe._

  /**
    * Returns a map from formal parameter names to types, containing one
    * mapping for each constructor argument.  The resulting map (a ListMap)
    * preserves the order of the primary constructor's parameter list.
    */
  def caseClassParamsOf[T: TypeTag]: ListMap[String, Type] = {
    val tpe = typeOf[T]
    val constructorSymbol = tpe.decl(termNames.CONSTRUCTOR)
    val defaultConstructor =
      if (constructorSymbol.isMethod) constructorSymbol.asMethod
      else {
        val ctors = constructorSymbol.asTerm.alternatives
        ctors.map(_.asMethod).find(_.isPrimaryConstructor).get
      }

    ListMap[String, Type]() ++ defaultConstructor.paramLists.reduceLeft(_ ++ _).map {
      sym => sym.name.toString -> tpe.member(sym.name).asMethod.returnType
    }
  }
person Connor Doyle    schedule 19.04.2013
comment
Я нахожу случаи, когда это не удается с scala.ScalaReflectionException: <none> is not a term в выражении constructorSymbol.asTerm.alternatives. Комментарий к документации для declaration ссылается на OverloadedSymbol, но похоже, что такого объекта не существует. - person Randall Schulz; 18.01.2014
comment
Оказывается, это происходило потому, что я вызывал его с this.type из признака, используемого в качестве супертипа рассматриваемого case-класса. - person Randall Schulz; 18.01.2014
comment
Кроме того, case class P(i: Int)(j: Int). - person som-snytt; 27.08.2014