最终编辑:所有极端情况都已解决,唯一的问题是我必须Encoder.encodeTraversableOnce
从 Circe 复制一个私有方法才能使Encoder
's 工作。我还必须更改MyCollection
为使用TraversableOnce
,而不仅仅是Traversable
(这是因为Encoder
' 仅适用于TraversableOnce
whereDecoder
与Traversable
. 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
where 一样)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
用我们想要的任何集合类型来一般地实例化 a,即
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:错误:不明确的隐式值:类型为 => generic.this.CanBuildFrom[String,scala.this.Char,String] 的模块类 Predef 中的 getter StringCanBuildFrom 和类型为 [ 的模块类 Predef 中的方法 $conforms A]=> $less$colon$less[A,A] 隐式匹配预期类型 T ^
有谁知道是什么导致了这个问题