【问题标题】:Converting a List to a Case Class将列表转换为案例类
【发布时间】:2015-11-21 06:47:25
【问题描述】:

作为一个练习,我想看看我是否可以使用 List[Any] 并使用 shapeless 将其“投射”到案例类中。

我正在努力实现的一个非常基本的示例:

case class Foo(i: Int, j: String)
val foo: Option[Foo] = fromListToCaseClass[Foo]( List(1:Any, "hi":Any) ) 

这是我正在制定我的解决方案的方式(这可能是完全不同的):

def fromListToCaseClass[CC <: Product](a: List[Any]): Option[CC] = a.toHList[???].map( x => Generic[CC].from(x) )

这是我的推理:

我知道你可以从一个案例类转到一个 HList[T] (CC -> HList[T]);其中 T 是 HList 的类型。我也知道,只要您知道 HList 的类型,就可以从列表 (list -> Option[HList]) 创建 HList。最后我知道您可以从 HList 转到案例类(HList -> CC)。

CC -> HList[T]
list -> Option[HList[T]] -> Option[CC]

我想知道这是否有意义,或者我是否离这里很远。我们可以完成这项工作吗?还有其他建议吗?谢谢!

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    这可以使用 shapeless 的 GenericFromTraversable 类型类非常简单地完成,

    import scala.collection.GenTraversable
    import shapeless._, ops.traversable.FromTraversable
    
    class FromListToCaseClass[T] {
      def apply[R <: HList](l: GenTraversable[_])
        (implicit gen: Generic.Aux[T, R], tl: FromTraversable[R]): Option[T] =
          tl(l).map(gen.from)
    }
    def fromListToCaseClass[T] = new FromListToCaseClass[T]
    

    (这里有一些意外的复杂性,因为 Scala 在混合显式类型参数和推断类型参数时很笨拙:我们想显式指定T,但为我们推断了R

    REPL 会话示例 ...

    scala> case class Foo(i: Int, j: String)
    defined class Foo
    
    scala> fromListToCaseClass[Foo](List(23, "foo"))
    res0: Option[Foo] = Some(Foo(23,foo))
    
    scala> fromListToCaseClass[Foo](List(23, false))
    res1: Option[Foo] = None
    

    【讨论】:

      【解决方案2】:

      你可以通过以下方式使用 shapeless:

      import shapeless._
      
      trait Creator[A] { def apply(list:List[Any]): Option[A] }
      
      object Creator {
        def as[A](list: List[Any])(implicit c: Creator[A]): Option[A] = c(list)
      
        def instance[A](parse: List[Any] => Option[A]): Creator[A] = new Creator[A] {
          def apply(list:List[Any]): Option[A] = parse(list)
        }
      
        def arbitraryCreate[A] = instance(list => list.headOption.map(_.asInstanceOf[A]))
      
        implicit val stringCreate = arbitraryCreate[String]
        implicit val intCreate = arbitraryCreate[Int]
        implicit val hnilCreate = instance(s => if (s.isEmpty) Some(HNil) else None)
      
        implicit def hconsCreate[H: Creator, T <: HList: Creator]: Creator[H :: T] =
      instance {
        case Nil => None
        case list => for {
          h <- as[H](list)
          t <- as[T](list.tail)
        } yield h :: t
      }
      
      implicit def caseClassCreate[C, R <: HList](
        implicit gen: Generic.Aux[C, R], 
        rc: Creator[R]): Creator[C] = 
          instance(s => rc(s).map(gen.from))
      }
      

      val foo:Option[Foo] = Creator.as[Foo](List(1, "hi"))
      

      【讨论】:

      • 很好的尝试,但您缺少TypeableFromTraversable,它们处理您尝试使用Creator 解决的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 2014-12-18
      • 1970-01-01
      • 2014-01-08
      相关资源
      最近更新 更多