construct case class from collection of parameters

本秂侑毒 提交于 2019-12-11 00:53:24

问题


Given:

case class Thing(a:Int, b:String, c:Double)

val v = Vector(1, "str", 7.3)

I want something that will magically create:

Thing(1, "str", 7.3)

Does such a thing exist (for arbitrary size Things)?


回答1:


My first time dipping my toes into the 2.10 experimental reflection facilities. So mostly following this outline http://docs.scala-lang.org/overviews/reflection/overview.html, I came up with this:

import scala.reflect.runtime.{universe=>ru}

case class Thing(a: Int, b: String, c: Double)

object Test {
  def main(args: Array[String]) {
    val v = Vector(1, "str", 7.3)
    val thing: Thing = Ref.runtimeCtor[Thing](v)
    println(thing) // prints: Thing(1,str,7.3)
  }
}

object Ref {
  def runtimeCtor[T: ru.TypeTag](args: Seq[Any]): T = {
    val typeTag = ru.typeTag[T]
    val runtimeMirror = ru.runtimeMirror(getClass.getClassLoader)

    val classSymbol = typeTag.tpe.typeSymbol.asClass
    val classMirror = runtimeMirror.reflectClass(classSymbol)

    val constructorSymbol = typeTag.tpe.declaration(ru.nme.CONSTRUCTOR).asMethod
    val constructorMirrror = classMirror.reflectConstructor(constructorSymbol)
    constructorMirrror(args: _*).asInstanceOf[T]
  }
}

Note that when I had the case class inside the main method, this did not compile. I don't know if type tags can only be generated for non-inner case classes.




回答2:


I don't know if it's possible to get a working solution with a compile-time error, but this is my solution using matching:

case class Thing(a: Int, b: String, c: Double)
def printThing(t: Thing) {
  println(t.toString)
}

implicit def vectToThing(v: Vector[Any]) = v match {
  case (Vector(a: Int, b: String, c: Double)) => new Thing(a, b, c)
}

val v = Vector(1, "str", 7.3) // this is of type Vector[Any]
printThing(v) // prints Thing(1,str,7.3)
printThing(Vector(2.0, 1.0)) // this is actually a MatchError

Is there an actual purpose to this "Thing"-conversion or would you rather use Tuple3[Int,String,Double] instead of Vector[Any]?




回答3:


From your question it's not clear what you will use it for. What you call a Thing might actually be a HList or a KList. HList stands for Heterogeneous Lists which is an "arbitrary-length tuple".

I am unsure how hard it would be to add an 'unnapply' or 'unapplySeq' method in order for it to behave more like a case class.

I have little experience with them, but a good explanation can be found here: http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/

If this is not what you need it might be a good idea to tell us what you want to achieve.



来源:https://stackoverflow.com/questions/14785054/construct-case-class-from-collection-of-parameters

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!