in Scala 3, I'm trying to instantiate a case class from a list of String, example
the list List("bob", "2.2", "1")
fit the fields of Foo
:
case class Foo(aString: String, aDouble: Double, aInt: Int)
and listStringTOclass[Foo](List("bob", "2.2", "1"))
returns Foo(bob,2.2,1)
But I can't retrive the types of Foo
elements, in my code I wrote val types = List("String", "Double", "Int")
but I should use MirroredElemTypes
to generalize, any help?
import scala.deriving.Mirror
import scala.compiletime.summonAll
def listStringTOclass[A](stringValues:List[String])(using m: Mirror.ProductOf[A]) = {
type TheType = String
type StringValue = String
val types = List("String","Double","Int") // m.MirroredElemTypes, should be Type not string
def valueList(ll: List[(TheType, StringValue)]): List[Any] = ll match {
case Nil => Nil
case h::t if h._2 == "String" => h._1 :: valueList(t)
case h::t if h._2 == "Int" => h._1.toInt :: valueList(t)
case h::t if h._2 == "Double" => h._1.toDouble :: valueList(t)
case _ => ???
}
val tv: List[(TheType, StringValue)] = stringValues.zip(types)
val l: List[Any] = valueList(tv)
println(l) // List(bob, 2.2, 1)
val tuple: Tuple = l.foldRight[Tuple](EmptyTuple)(_ *: _)
println(tuple) // (bob,2.2,1)
m.fromProduct(tuple)
}
case class Foo(aString: String, aDouble: Double, aInt: Int)
val o = listStringTOclass[Foo](List("bob", "2.2", "1"))
println(o) // Foo(bob,2.2,1)
CodePudding user response:
How about this (works in scala 3.0.1):
scala> object list2class {
| import scala.deriving.Mirror
|
| trait Decoder[A, B] extends (A => B)
| object Decoder:
| given Decoder[String, String] = s => s
| given Decoder[String, Int] = _.toInt
| given Decoder[String, Double] = _.toDouble
| given Decoder[List[String], EmptyTuple] = {
| case Nil => EmptyTuple
| case s => throw IllegalArgumentException(s.toString())
| }
| given [H, T <: Tuple](using dh: Decoder[String, H], dt: Decoder[List[String], T]): Decoder[List[String], H *: T] = {
| case h::t => dh(h) *: dt(t)
| case Nil => throw IndexOutOfBoundsException()
| }
|
| def apply[A](xs: List[String])(using m: Mirror.ProductOf[A], d: Decoder[List[String], m.MirroredElemTypes]): A =
| m.fromProduct(d(xs))
| }
// defined object list2class
scala> case class Foo(aString: String, aDouble: Double, aInt: Int)
// defined case class Foo
scala> list2class[Foo](List("bob", "2.2", "1"))
val res0: Foo = Foo(bob,2.2,1)
CodePudding user response:
Consider using shapeless for semi-automatic case class derivation via HList "heterogeneous list".