How can I create an instance of a Case Class with constructor arguments with no Parameters in Scala?

后端 未结 4 1866
清歌不尽
清歌不尽 2020-12-10 17:23

I\'m making a Scala app that sets by reflection field values. This works OK.

However, in order to set field values I need a created instance. If I have a class with

4条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-10 18:00

    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]())
    }
    

提交回复
热议问题