将哈希映射键/值对映射到 Scala 中的命名构造函数参数 [英] Mapping hash map key/value pairs to named constructor arguments in Scala

查看:50
本文介绍了将哈希映射键/值对映射到 Scala 中的命名构造函数参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以将 Map 的键值对映射到带有命名参数的 Scala 构造函数?

Is it possible to map the key value pairs of a Map to a Scala constructor with named parameters?

即给定

class Person(val firstname: String, val lastname: String) {
    ...
}

...如何使用像

val args = Map("firstname" -> "John", "lastname" -> "Doe", "ignored" -> "value")

我最终想要实现的是一种将 Node4J Node 对象映射到 Scala 值对象的好方法.

What I am trying to achieve in the end is a nice way of mapping Node4J Node objects to Scala value objects.

推荐答案

这里的关键见解是构造函数参数名称​​是可用的,因为它们是由构造函数创建的字段的名称.所以假设构造函数不对其参数做任何处理,而是将它们分配给字段,那么我们可以忽略它并直接使用字段.

The key insight here is that the constructor arguments names are available, as they are the names of the fields created by the constructor. So provided that the constructor does nothing with its arguments but assign them to fields, then we can ignore it and work with the fields directly.

我们可以使用:

def setFields[A](o : A, values: Map[String, Any]): A = {
  for ((name, value) <- values) setField(o, name, value)
  o
}

def setField(o: Any, fieldName: String, fieldValue: Any) {
  // TODO - look up the class hierarchy for superclass fields
  o.getClass.getDeclaredFields.find( _.getName == fieldName) match {
    case Some(field) => {
      field.setAccessible(true)
      field.set(o, fieldValue)
    }
    case None =>
      throw new IllegalArgumentException("No field named " + fieldName)
  }

我们可以调用一个空白的人:

Which we can call on a blank person:

test("test setFields") {
  val p = setFields(new Person(null, null, -1), Map("firstname" -> "Duncan", "lastname" -> "McGregor", "age" -> 44))
  p.firstname should be ("Duncan")
  p.lastname should be ("McGregor")
  p.age should be (44)
}

当然,我们可以通过拉皮条做得更好:

Of course we can do better with a little pimping:

implicit def any2WithFields[A](o: A) = new AnyRef {
  def withFields(values: Map[String, Any]): A = setFields(o, values)
  def withFields(values: Pair[String, Any]*): A = withFields(Map(values :_*))
}

以便您可以调用:

new Person(null, null, -1).withFields("firstname" -> "Duncan", "lastname" -> "McGregor", "age" -> 44)

<小时>

如果必须调用构造函数很烦人,Objenesis 可以让您忽略无参数构造函数的缺失:


If having to call the constructor is annoying, Objenesis lets you ignore the lack of a no-arg constructor:

val objensis = new ObjenesisStd 

def create[A](implicit m: scala.reflect.Manifest[A]): A = 
  objensis.newInstance(m.erasure).asInstanceOf[A]

现在我们可以将两者结合起来写

Now we can combine the two to write

create[Person].withFields("firstname" -> "Duncan", "lastname" -> "McGregor", "age" -> 44)

这篇关于将哈希映射键/值对映射到 Scala 中的命名构造函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆