在 Scala/Java 中获取实例的公共字段(及其各自的值)

发布于 2024-12-05 06:41:48 字数 693 浏览 0 评论 0原文

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

PHP introduces a method that allows you to pick out all public values of an instance. Is there any way to do this in Scala? That is to fetch all values of all public fields of an instantiated class (not object).

Let's us assume I have this class

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 );

What I need from the method in question, is to get a Map or two Collections of values.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

Saygoodbye 2024-12-12 06:41:48

该睡觉了,所以我没有时间给出完整的答案,但看看 element.getClass.getFields (或 getDeclaredFields 对于私有字段)的结果 -您可以在 Field 对象上调用 getValue(element) 来获取它们的值。


现在清醒了,仍然没有更好的答案,所以:

首先,请注意,用 Java 术语来说,您的类没有公共字段主题,它拥有的是私有字段主题和访问器方法 subject() 和 subject_$eq(String )。

您可以如上所述迭代私有字段对象,从对中填充 Map:

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 

就会得到您想要的结果。

It's time for bed, so I don't have time for a full answer, but look at the results of element.getClass.getFields (or getDeclaredFields for private fields) - you can call getValue(element) on the Field objects to fetch their values.


Awake now, and still no better answer, so:

First, note that in Java terms, your class doesn't have a public field subject, what it has is a private field subject and accessor methods subject() and subject_$eq(String).

You can iterate over the private field objects as described above, populating a Map from the pairs:

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 :_*)
}

Now you can either define this method on TestElement (replacing o with this), or more generally usefully define a conversion so that you can call getFields on any reference

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

So that

element.fieldValues 

will give the result you want.

╰◇生如夏花灿烂 2024-12-12 06:41:48

根据菲利普的回答,您可以对案例类执行此操作。

但更广泛地说,相同的技术适用于 Product任何子类。除了案例类之外,元组是另一个明显的例子,但列表远不止于此。

在这里查看“已知子类”: http://www .scala-lang.org/api/current/scala/Product.html

A per Philippe's answer, you can do this for case classes.

More broadly though, the same technique works for any subclass of Product. As well as case classes, Tuples are another obvious example, but the list is far more extensive than that.

Take a look at the "known subclasses", here: http://www.scala-lang.org/api/current/scala/Product.html

衣神在巴黎 2024-12-12 06:41:48

对于案例类,您可以做一些与此相对接近的事情:

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 的发布。

You can do something relatively close to this for case classes:

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

...as you would expect, productIterator iterates over elements of type Any. This method is automatically generated for case classes only, and you will not retrieve the name of the field. For anything more, you will need to use reflection, and for that, you may want to wait for 2.10 to come out.

悲凉≈ 2024-12-12 06:41:48

只是给那些试图通过制作@Duncan的方法类型的人的注释:

而不是返回map [string,任何],其中值是键入的,您可以执行下列的:

def propertiesAsPairs() = {
    val fields = (this.getClass.getDeclaredFields())
    for ( field <- fields ) yield {
        field.setAccessible( true );
        ( field.getName, field.get( this ) );
    }
}

Just a note to those who try to improve this by making @duncan 's approach type-stronger:

Instead of returning a Map[String, Any], where the value is typed as Any, you could do following:

def propertiesAsPairs() = {
    val fields = (this.getClass.getDeclaredFields())
    for ( field <- fields ) yield {
        field.setAccessible( true );
        ( field.getName, field.get( this ) );
    }
}
北风几吹夏 2024-12-12 06:41:48

Scala故意制作valvardef共享一个共同的接口,因此您可以用后者替换前两个而不会破坏任何代码 - 甚至不需要重新编译。

因此,虽然可以做您想做的事情,但它会导致脆弱的代码,而这种代码不应该做。

Scala deliberately makes val, var and def share a common interface, so you can replace the former two with the latter without breaking any code -- without even requiring a recompile.

So, while it is possible to do what you want, it would result in brittle code, that does the sort of thing it shouldn't do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文