Получаване на публични полета (и съответните им стойности) на екземпляр в Scala/Java

PHP въвежда метод, който ви позволява да изберете всички публични стойности на екземпляр. Има ли някакъв начин да направите това в Scala? Това означава да извлечете всички стойности на всички публични полета на инстанциран клас (не обект).

Да приемем, че имам този клас

class TestElement( datatype: Datatype, var subject: String, var day: Int, var time: Int )
  extends DataElement( datatype: Datatype ) {    
   def to( group: Group ) = group.add( this );
}

var element = new TestElement( datatype, "subject", 1, 1 );

Това, от което се нуждая от въпросния метод, е да получа карта или две колекции от стойности.

var element.method                                       // the function I need
ret: ( ("subject", "subject"), ("day", 1), ("time", 1) ) // its output

person sdkfasldf    schedule 17.09.2011    source източник


Отговори (5)


Време е за лягане, така че нямам време за пълен отговор, но вижте резултатите от element.getClass.getFields (или getDeclaredFields за частни полета) - можете да извикате getValue(element) на Field обектите, за да извлечете техните стойности.


Събуди се сега и все още няма по-добър отговор, така че:

Първо, имайте предвид, че в термините на Java вашият клас няма предмет на публично поле, това, което има, е субект на частно поле и методи за достъп subject() и subject_$eq(String).

Можете да итерирате частните полеви обекти, както е описано по-горе, като попълвате карта от двойките:

def getFields(o: Any): Map[String, Any] = {
  val fieldsAsPairs = for (field <- o.getClass.getDeclaredFields) yield {
    field.setAccessible(true)
    (field.getName, field.get(o)) 
  }
  Map(fieldsAsPairs :_*)
}

Сега можете или да дефинирате този метод на TestElement (като замените o с this), или по-общо полезно да дефинирате преобразуване, така че да можете да извикате getFields за всяка препратка

implicit def any2FieldValues[A](o: A) = new AnyRef {
  def fieldValues = getFields(o)
}

Така че

element.fieldValues 

ще даде резултата, който желаете.

person Duncan McGregor    schedule 17.09.2011
comment
Какво прави синтаксисът :_*? - person Ali; 01.02.2018

Според отговора на Филип, можете да направите това за класове по случай.

В по-широк план обаче същата техника работи за всеки подклас на Product. Освен класовете case, Tuples са друг очевиден пример, но списъкът е много по-обширен от това.

Разгледайте „известните подкласове“ тук: http://www.scala-lang.org/api/current/scala/Product.html

person Kevin Wright    schedule 18.09.2011

Можете да направите нещо относително близко до това за класове case:

case class SomeEntity(name : String, value : Int, misc : Boolean)
val s = SomeEntity("Tom", 42, false)
println(s.productIterator.map(_.toString).mkString(", ")) // "Tom, 42, false"

... както бихте очаквали, productIterator итерира елементи от тип Any. Този метод се генерира автоматично само за класове случаи и няма да извлечете името на полето. За всичко повече ще трябва да използвате отражение и за това може да искате да изчакате 2.10 да излезе.

person Philippe    schedule 17.09.2011

Само бележка за онези, които се опитват да подобрят това, като направят подхода на @duncan по-силен:

Вместо да връщате Map[String, Any], където стойността е въведена като Any, можете да направите следното:

def propertiesAsPairs() = {
    val fields = (this.getClass.getDeclaredFields())
    for ( field <- fields ) yield {
        field.setAccessible( true );
        ( field.getName, field.get( this ) );
    }
}
person sdkfasldf    schedule 18.09.2011
comment
Какъв е типът връщане на това? Прилича ми на Array[Pair[String, Any]], който не ви е купил нищо? - person Duncan McGregor; 19.09.2011

Scala умишлено кара val, var и def да споделят общ интерфейс, така че можете да замените първите два с втория, без да нарушавате какъвто и да е код - без дори да се налага повторно компилиране.

Така че, въпреки че е възможно да правите това, което искате, това ще доведе до нестабилен код, който прави нещо, което не трябва да прави.

person Daniel C. Sobral    schedule 19.09.2011
comment
Мисля, че бих казал, че за класове данни като този смисълът е просто да се прехвърлят стойности в полета. - person Duncan McGregor; 19.09.2011