Given:
case class Foo(a: Int, b: String, c: Double)
you can say:
val params = Foo(1, "bar", 3.14).productIterator.toList
and get:
params: List[Any] = List(1, bar, 3.14)
Is there a way to "go backwards" and recreate a Foo object directly from this list, i.e.:
Foo.createFromList(params) // hypothetical
instead of writing:
Foo(params(0).asInstanceOf[Int], params(1).asInstanceOf[String], params(2).asInstanceOf[Double])
EDIT: it seems that it boils down to being able to send the elements of a list as parameters to a function without writing them out explicitly, e.g.:
def bar(a: Int, b: Int, c: Int) = //... val list = List(1, 2, 3, 4, 5) bar(list.take(3)) // hypothetical, instead of: bar(list(0), list(1), list(2))
I would sort of expect to be able to do:
bar(list.take(3): _*)
but that doesn't seem to work.
EDIT: Solution based on extempore's answer, but invoking the constructor directly instead of using the apply method:
case class Foo(a: Int = 0, b: String = "bar", c: Double = 3.14) { val cs = this.getClass.getConstructors def createFromList(params: List[Any]) = cs(0).newInstance(params map { _.asInstanceOf[AnyRef] } : _*).asInstanceOf[Foo] }
Now you can do:
scala> Foo().createFromList(List(4, "foo", 9.81)) res13: Foo = Foo(4,foo,9.81)
You can also refactor the creation method into a trait:
trait Creatable[T <: Creatable[T]] { val cs = this.getClass.getConstructors def createFromList(params: List[Any]) = cs(0).newInstance(params map { _.asInstanceOf[AnyRef] } : _*).asInstanceOf[T] } case class Bar(a: Int = 0, b: String = "bar", c: Double = 3.14) extends Creatable[Bar]
And do e.g.:
scala> val bar = Bar() bar: Bar = Bar(0,bar,3.14) scala> bar == bar.createFromList(bar.productIterator.toList) res11: Boolean = true
A class can extend another class, whereas a case class can not extend another case class (because it would not be possible to correctly implement their equality).
It can contain both state and functionality. Case classes are like data POJO in Java. classes that hold state, which can be used by functions (usually in other classes).
Note: The Case class has a default apply () method which manages the construction of object. A Case Object is also like an object, which has more attributes than a regular Object. It is a blend of both case classes and object. A case object has some more features than a regular object.
Parameters are like constants that are local to the specified class. Classes are allowed to have default value for each parameter that can be overridden during class instantiation. Given below is a parameterized class which has size as the parameter that can be changed during instantiation.
Instantiating an object in Python consists of a few stages, but the beauty of it is that they are Pythonic in themselves - understanding the steps gives us a little bit more understanding of Python in general. Foois a class, but classes in Python are objects too!
It has a by default hashCode implementation. The one of the topmost benefit of Case Class is that Scala Compiler affix a method with the name of the class having identical number of parameters as defined in the class definition, because of that you can create objects of the Case Class even in the absence of the keyword new.
scala> case class Foo(a: Int, b: String, c: Double) defined class Foo scala> val params = Foo(1, "bar", 3.14).productIterator.toList params: List[Any] = List(1, bar, 3.14) scala> Foo.getClass.getMethods.find(x => x.getName == "apply" && x.isBridge).get.invoke(Foo, params map (_.asInstanceOf[AnyRef]): _*).asInstanceOf[Foo] res0: Foo = Foo(1,bar,3.14) scala> Foo(1, "bar", 3.14) == res0 res1: Boolean = true
Edit: by the way, the syntax so far only being danced around for supplying the tuple as an argument is:
scala> case class Foo(a: Int, b: String, c: Double) defined class Foo scala> Foo.tupled((1, "bar", 3.14)) res0: Foo = Foo(1,bar,3.14)
You could use pattern matching like:
params match { case List(x:Int, y:String, d:Double) => Foo(x,y,d) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With