无形 .toHList 的行为
Behavior of shapeless .toHList
编译如下:
object Run1 extends App {
import shapeless._
import syntax.std.traversable._
case class Container[T](x: T)
Seq(Container(1), Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
}
但这不是:
object Run2 extends App {
import shapeless._
import syntax.std.traversable._
class Container[T](val x: T)
Seq(new Container(1), new Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
}
失败并出现以下错误:
Error:(40, 52) could not find implicit value for parameter fl: shapeless.ops.traversable.FromTraversable[shapeless.:: [com.adaje.service.table.Run2.Container[Int],shapeless.::[com.adaje.service.table.Run2.Container[String],shapeless.HNil]]]
Seq(new Container(1), new Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
^
为什么第二个程序不起作用,有什么可以添加的吗?
谢谢
FromTraversable
类型 class 需要 Typeable
个元素类型实例。 Shapeless 为案例 classes 提供了这些现成的,但不为任意定义的 classes。不过,您可以很容易地定义自己的:
import shapeless._, shapeless.syntax.std.traversable._
class Container[T](val x: T)
implicit def containerTypeable[A: Typeable]: Typeable[Container[A]] =
new Typeable[Container[A]] {
def cast(t: Any): Option[Container[A]] = t match {
case c: Container[_] => Typeable[A].cast(c.x).map(new Container(_))
case _ => None
}
def describe: String = s"Container[${ Typeable[A].describe }]"
}
然后:
scala> val cs = Seq(new Container(1), new Container("x"))
cs: Seq[Container[_ >: String with Int]] = List(Container@3c3c89b2, Container@1273a053)
scala> cs.toHList[Container[Int] :: Container[String] :: HNil]
res0: Option[shapeless.::[Container[Int],shapeless.::[Container[String],shapeless.HNil]]] = Some(Container@357c808b :: Container@607bcaf5 :: HNil)
还有:
scala> cs.reverse.toHList[Container[Int] :: Container[String] :: HNil]
res1: Option[shapeless.::[Container[Int],shapeless.::[Container[String],shapeless.HNil]]] = None
scalac 的 -Xlog-implicits
选项在这种情况下会很方便——它会清楚地表明您最初的非 case-class 尝试中缺少的是 Typeable
实例。
编译如下:
object Run1 extends App {
import shapeless._
import syntax.std.traversable._
case class Container[T](x: T)
Seq(Container(1), Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
}
但这不是:
object Run2 extends App {
import shapeless._
import syntax.std.traversable._
class Container[T](val x: T)
Seq(new Container(1), new Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
}
失败并出现以下错误:
Error:(40, 52) could not find implicit value for parameter fl: shapeless.ops.traversable.FromTraversable[shapeless.:: [com.adaje.service.table.Run2.Container[Int],shapeless.::[com.adaje.service.table.Run2.Container[String],shapeless.HNil]]]
Seq(new Container(1), new Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
^
为什么第二个程序不起作用,有什么可以添加的吗?
谢谢
FromTraversable
类型 class 需要 Typeable
个元素类型实例。 Shapeless 为案例 classes 提供了这些现成的,但不为任意定义的 classes。不过,您可以很容易地定义自己的:
import shapeless._, shapeless.syntax.std.traversable._
class Container[T](val x: T)
implicit def containerTypeable[A: Typeable]: Typeable[Container[A]] =
new Typeable[Container[A]] {
def cast(t: Any): Option[Container[A]] = t match {
case c: Container[_] => Typeable[A].cast(c.x).map(new Container(_))
case _ => None
}
def describe: String = s"Container[${ Typeable[A].describe }]"
}
然后:
scala> val cs = Seq(new Container(1), new Container("x"))
cs: Seq[Container[_ >: String with Int]] = List(Container@3c3c89b2, Container@1273a053)
scala> cs.toHList[Container[Int] :: Container[String] :: HNil]
res0: Option[shapeless.::[Container[Int],shapeless.::[Container[String],shapeless.HNil]]] = Some(Container@357c808b :: Container@607bcaf5 :: HNil)
还有:
scala> cs.reverse.toHList[Container[Int] :: Container[String] :: HNil]
res1: Option[shapeless.::[Container[Int],shapeless.::[Container[String],shapeless.HNil]]] = None
scalac 的 -Xlog-implicits
选项在这种情况下会很方便——它会清楚地表明您最初的非 case-class 尝试中缺少的是 Typeable
实例。