将列表转换为案例 Class
Converting a List to a Case Class
作为练习,我想看看我是否可以使用 shapeless 将 List[Any]
和 "cast" 放入案例 class 中。
我正在努力实现的一个非常基本的例子:
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) )
这是我的推理:
我知道您可以从案例 class 转到 HList[T] (CC -> HList[T]);其中 T 是 HList 的类型。我还知道,只要知道 HList 的类型,就可以从列表 (list -> Option[HList]) 创建 HList。最后我知道你可以从一个 HList 转到一个案例 class (HList -> CC)。
CC -> HList[T]
list -> Option[HList[T]] -> Option[CC]
我想知道这是否有意义,或者我是否离题太远了。我们能做到吗?还有其他建议吗?谢谢!
您可以通过以下方式使用 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"))
这可以使用 shapeless 的 Generic
和 FromTraversable
类型 类,
非常直接地完成
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
作为练习,我想看看我是否可以使用 shapeless 将 List[Any]
和 "cast" 放入案例 class 中。
我正在努力实现的一个非常基本的例子:
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) )
这是我的推理:
我知道您可以从案例 class 转到 HList[T] (CC -> HList[T]);其中 T 是 HList 的类型。我还知道,只要知道 HList 的类型,就可以从列表 (list -> Option[HList]) 创建 HList。最后我知道你可以从一个 HList 转到一个案例 class (HList -> CC)。
CC -> HList[T]
list -> Option[HList[T]] -> Option[CC]
我想知道这是否有意义,或者我是否离题太远了。我们能做到吗?还有其他建议吗?谢谢!
您可以通过以下方式使用 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"))
这可以使用 shapeless 的 Generic
和 FromTraversable
类型 类,
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