我正在使用Shapeless,并具有以下方法来计算两个HList之间的差异:
def diff[H <: HList](lst1: H, lst2:H):List[String] = (lst1, lst2) match {
case (HNil, HNil) => List()
case (h1::t1, h2::t2) if h1 != h2 => s"$h1 -> $h2" :: diff(t1, t2)
case (h1::t1, h2::t2) => diff(t1, t2)
case _ => throw new RuntimeException("something went very wrong")
}
由于该方法的两个参数均采用
H
,因此我希望此处不编译不同类型的HList。例如:diff("a" :: HNil, 1 :: 2 :: HNil)
不应该编译,但是可以编译,并且会生成运行时错误:
java.lang.RuntimeException: something went very wrong
。我可以对类型参数做些什么,使该方法只接受具有相同类型的两侧? 最佳答案
不幸的是,基本的HList
特征是未参数化的,因此在您的方法调用中,H
只是解析为Hlist
(这实际上是任何Hlist
的超类型,而与具体的元素类型无关)。
为了解决这个问题,我们必须对定义进行一些更改,而要依靠广义类型约束:
def diff[H1 <: HList, H2 <: HList](lst1: H1, lst2: H2)(implicit e: H1 =:= H2): List[String] = (lst1, lst2) match {
case (HNil, HNil) => List()
case (h1::t1, h2::t2) if h1 != h2 => s"$h1 -> $h2" :: diff(t1, t2)
case (h1::t1, h2::t2) => diff(t1, t2)
case _ => throw new RuntimeException("something went very wrong")
}
让我们检查:
scala> diff("a" :: HNil, 1 :: 2 :: HNil)
<console>:12: error: Cannot prove that shapeless.::[String,shapeless.HNil] =:= shapeless.::[Int,shapeless.::[Int,shapele
diff("a" :: HNil, 1 :: 2 :: HNil)
^
scala> diff("a" :: HNil, "b" :: HNil)
res5: List[String] = List(a -> b)
scala> diff("a" :: 1 :: HNil, "b" :: 2 :: HNil)
res6: List[String] = List(a -> b, 1 -> 2)
现在我们仍然可以“作弊”,并将H1和H2显式设置为
HList
,然后回到平方。scala> diff[HList, HList]("a" :: HNil, 1 :: 2 :: HNil)
java.lang.RuntimeException: something went very wrong
at .diff(<console>:15)
at .diff(<console>:13)
不幸的是,我认为这不容易解决(虽然确实如此,但是我没有快速解决方案)。