如何在 Scala 中使用没有参数的构造函数参数创建案例类的实例? [英] How can I create an instance of a Case Class with constructor arguments with no Parameters in Scala?
问题描述
我正在制作一个通过反射字段值设置的 Scala 应用程序.这工作正常.
I'm making a Scala app that sets by reflection field values. This works OK.
但是,为了设置字段值,我需要一个已创建的实例.如果我有一个带有空构造函数的类,我可以使用 classOf[Person].getConstructors.... 轻松做到这一点.
However, in order to set field values I need a created instance. If I have a class with an empty constructor, I can do this easily with classOf[Person].getConstructors....
但是,当我尝试使用具有非空构造函数的 Case 类执行此操作时,它不起作用.我拥有所有字段名称及其值,以及我需要创建的 Object 类型.我可以用我所拥有的东西以某种方式实例化案例类吗?
However, when I try doing this with a Case class with a non empty constructor It doesn't work. I have all of the field names and its values, as well as the Object type I need to create. Can I instance the Case Class somehow with what I've got?
我唯一没有的是 Case Class 构造函数中的参数名称,或者是在没有参数的情况下创建它然后通过反射设置值的方法.
The only thing I don't have is the parameter names from the Case Class constructor or a way to create this without parameter and then setting the values via reflection.
我们来看例子.
我有以下
case class Person(name : String, age : Int)
class Dog(name : String) {
def this() = {
name = "Tony"
}
}
class Reflector[O](obj : O) {
def setValue[F](propName : String, value : F) = ...
def getValue(propName : String) = ...
}
//This works
val dog = classOf[Dog].newInstance()
new Reflector(dog).setValue("name", "Doggy")
//This doesn't
val person = classOf[Person].newInstance //Doesn't work
val ctor = classOf[Person].getConstructors()(0)
val ctor.newInstance(parameters) //I have the property names and values, but I don't know
// which of them is for each parameter, nor I name the name of the constructor parameters
推荐答案
case类应该有默认的args,这样你就可以Person()
;在没有默认参数的情况下,为 name 提供 null 可能(或应该)命中 require(name != null).
The case class should have default args, so that you can just Person()
; in the absence of a default arg, supplying a null for name might (or ought to) hit a require(name != null).
或者,使用反射来确定哪些参数具有默认值,然后为其余参数提供空值或零.
Alternatively, use reflection to figure out which params have defaults and then supply nulls or zeros for the rest.
import reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
// case class instance with default args
// Persons entering this site must be 18 or older, so assume that
case class Person(name: String, age: Int = 18) {
require(age >= 18)
}
object Test extends App {
// Person may have some default args, or not.
// normally, must Person(name = "Guy")
// we will Person(null, 18)
def newCase[A]()(implicit t: ClassTag[A]): A = {
val claas = cm classSymbol t.runtimeClass
val modul = claas.companionSymbol.asModule
val im = cm reflect (cm reflectModule modul).instance
defaut[A](im, "apply")
}
def defaut[A](im: InstanceMirror, name: String): A = {
val at = newTermName(name)
val ts = im.symbol.typeSignature
val method = (ts member at).asMethod
// either defarg or default val for type of p
def valueFor(p: Symbol, i: Int): Any = {
val defarg = ts member newTermName(s"$name$$default$$${i+1}")
if (defarg != NoSymbol) {
println(s"default $defarg")
(im reflectMethod defarg.asMethod)()
} else {
println(s"def val for $p")
p.typeSignature match {
case t if t =:= typeOf[String] => null
case t if t =:= typeOf[Int] => 0
case x => throw new IllegalArgumentException(x.toString)
}
}
}
val args = (for (ps <- method.paramss; p <- ps) yield p).zipWithIndex map (p => valueFor(p._1,p._2))
(im reflectMethod method)(args: _*).asInstanceOf[A]
}
assert(Person(name = null) == newCase[Person]())
}
这篇关于如何在 Scala 中使用没有参数的构造函数参数创建案例类的实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!