【发布时间】:2018-07-20 15:14:12
【问题描述】:
最终编辑:所有极端情况都已解决,唯一的问题是我必须从 Circe 复制私有 Encoder.encodeTraversableOnce 方法才能使 Encoder 正常工作。我还必须将MyCollection 更改为使用TraversableOnce 而不仅仅是Traversable(这是因为Encoder 只能与TraversableOnce 一起使用,而Decoder 与Traversable 一起使用。演示所有案例都可以在这里找到https://scalafiddle.io/sf/F5Qo8cn/15。
小提琴可以在这里找到https://scalafiddle.io/sf/F5Qo8cn/8
基本上我正在尝试对集合类型进行抽象,这是在包含可遍历集合的模型的上下文中,即假设我们有以下内容
case class MyCollection[C[A] <: Traversable[A]](stuff: C[String])
这允许我们使用特定的集合类型来实例化MyCollection,即
val innerV = MyCollection(Vector("a"))
val innerL = MyCollection(List("b"))
MyCollection 也恰好有一个具体的类型,所以当我们访问.stuff 方法时,它将返回我们用来创建它的类型(即,在innerV 的情况下,它的Vector 是与innerL 其List)
由于这是 Web 框架的上下文,MyCollection 恰好代表一些 JSON,因此使用 Circe 0.9.1 我们可以编写如下解码器
object MyCollection {
implicit def decoder[C[A] <: Traversable[A]]: Decoder[MyCollection[C]] = {
new Decoder[MyCollection[C]] {
override def apply(c: HCursor) = {
c.downField("stuff").as[C[String]](Decoder.decodeTraversable[String, C](
implicitly,
implicitly
))
}.map((x: C[String]) => MyCollection.apply(x))
}
}
}
请注意,我们显式调用implicit 参数以及手动编写解码器,以便我们可以帮助跟踪隐式问题所在。这个想法是我们可以用我们想要的任何集合类型来一般地实例化case class,即
def getMyCollection[C[A] <: Traversable[A]]: MyCollection[C] = {
val jsonString = """{ "stuff": ["a","b"] }"""
val json = io.circe.parser.parse(jsonString).right.get
json.as[MyCollection[C]].right.get
}
def asVector: MyCollection[Vector] = getMyCollection[Vector]
def asList: MyCollection[List] = getMyCollection[List]
问题是我得到了一个不同的隐式扩展,特别是在这一行
c.downField("stuff").as[C[String]](Decoder.decodeTraversable[String, C](
implicitly,
implicitly // <- error happens here, this is a CBF implicit
))
我们得到的错误是
ScalaFiddle.scala:19: 错误: 模糊的隐含值: 两个 getter 类型为 Predef 的模块类中的 StringCanBuildFrom => generic.this.CanBuildFrom[String,scala.this.Char,String] 和方法 [A]=> $less$colon$less[A,A] 类型的模块类 Predef 中的 $conforms 匹配预期类型 T 含蓄地 ^
有谁知道这个问题的原因
【问题讨论】:
标签: scala collections implicit scala-cats circe