【问题标题】:Scala 3 - Instantiate class from List[String]Scala 3 - 从 List[String] 实例化类
【发布时间】:2021-11-03 15:45:33
【问题描述】:

在 Scala 3 中,我试图从字符串列表中实例化一个案例类,例如

列表List("bob", "2.2", "1") 适合Foo 的字段:

case class Foo(aString: String, aDouble: Double, aInt: Int)

listStringTOclass[Foo](List("bob", "2.2", "1")) 返回Foo(bob,2.2,1)

但我无法检索 Foo 元素的类型,在我的代码中我写了 val types = List("String", "Double", "Int") 但我应该使用 MirroredElemTypes 进行概括,有什么帮助吗?

    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)

【问题讨论】:

  • 您是在尝试编写 CSV 解析器或类似的东西吗?
  • 据我了解您的问题,您可以在这种情况下使用反射(无论是运行时还是编译时,例如,如果您使用了 play json,Json.writer[T] 会为在编译时键入 T,但将 json 解析为对象是在运行时完成的),您可以访问类型或对象的公共和私有字段名称、方法和类型以及许多其他内容。而且,如果你的 Foo 类有另一个复杂类的对象会发生什么?所以我建议你使用反射。
  • 这可能会有所帮助:stackoverflow.com/questions/14722860/…,然后案例类的元组是 OOB

标签: scala scala-3


【解决方案1】:

这个怎么样(在 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)

【讨论】:

    【解决方案2】:

    考虑使用shapeless 通过 HList“异构列表”进行半自动案例类派生。

    【讨论】:

    • 问题是关于 Scala 3
    • IMO 这将是一个更好的评论而不是一个答案。
    猜你喜欢
    • 1970-01-01
    • 2019-05-08
    • 2013-08-15
    • 2017-10-25
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    相关资源
    最近更新 更多