为什么我似乎无法正确地将无形记录与选项合并?

Why can't I seem to merge shapeless records with Options correctly?

如果我按如下方式合并两条记录:

case object Key
val a = (Key ->> Option.empty[String]) :: HNil
val b = (Key ->> Option("plif")) :: HNil
val c = a.merge(b)

然后正如我们所期望的那样 b == c。但是,如果我对 a 使用普通字符串而不是 None 那么这就不再是真的了:

case object Key
val a = (Key ->> "pluf") :: HNil
val b = (Key ->> Option("plif")) :: HNil
val c = a.merge(b)

在这种情况下 c 结果是:"pluf" :: Some("plif") :: HNilc.keysKey :: Key :: HNil。给出了什么?

我正在使用 Shapeless 2.1,如果这有什么不同的话。

我假设被合并的类型必须与合并一致。也就是说,它们必须属于同一类型。在第一种情况下,您有 2 个 Option[String] 类型,而在第二种情况下,您有一个 Option[String] 和一个 String.

查看代码 (https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/ops/records.scala#L157-L192) 并研究隐式逻辑以了解 Merger 的工作原理:

  1. 我们可以看到具有最高优先级(https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/ops/records.scala#L179-L191)的implicit更喜欢记录之间的值类型匹配。它替换合并记录输出中的值。
  2. 较低的优先级implicit (https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/ops/records.scala#L162-L167) 仅在类型不匹配时激活,附加头部和 然后迭代向下遍历记录的结构。
  3. 最后,在 HNil 的情况下,它只是将第二条记录中所有其他操作之后剩余的内容附加到第一条记录。也就是说,如果它们的尺寸不匹配,它会采用其他可用的方式。