None Typeclass 的隐式查找与 Option 的 Contravariant Typeclass 不兼容

Implicit lookup for Typeclass of None is not compatible with Contravariant Typeclass of Option

我没有得到以下代码来编译,我很好奇我做错了什么。

我定义了一个 Contravariant Jsonwriter Trait 和一个接受隐式编写器的函数:

trait JsonWriter[-A] {
  def write(value: A): Json
}

object Json {
  def toJson[A](value: A)(implicit writer: JsonWriter[A]): Json =
  writer.write(value)
}

此外,我还定义了这些作者的一些实例:

object JsonWriterInstances {
  implicit val stringWriter: JsonWriter[String] =
    (value: String) => JsString(value)

  implicit val doubleWriter: JsonWriter[Double] =
    (value: Double) => JsNumber(value)

  class OptionWriter[-T](writer: JsonWriter[T]) extends JsonWriter[Option[T]] {
    def write(value: Option[T]): Json = {
        value match {
          case None    => JsNull
          case Some(x) => writer.write(x)
        }
      }
  }
  implicit def optionWriter[T](implicit writer: JsonWriter[T]):
      JsonWriter[Option[T]] = new OptionWriter[T](writer)

}

现在我写了一个测试:

"write double Option" in {
  Some(1.0).toJson should be(JsNumber(1.0))
  None.toJson should be(JsNull)
}

Some(1.0) 的第一个测试工作正常 None 的第二个抛出:

Error:(40, 12) could not find implicit value for parameter writer: JsonWriter[None.type]
    None.toJson should be(JsNull)

如果您想尝试代码,我对这个示例的 JsonType 定义是:

sealed trait Json

final case class JsObject(get: Map[String, Json]) extends Json

final case class JsString(get: String) extends Json

final case class JsNumber(get: Double) extends Json

case object JsNull extends Json

我认为这与以下事实有关

case object None extends Option[Nothing] { ... }

如果您执行以下操作之一,它将起作用

toJson(Option.empty[Double])
toJson(None : Option[Double])

请注意,第二个使用 type ascriptionNothing(它是所有内容的子类型)

上放置一个面孔,可以这么说

None,不说别的,就是一个Option[Nothing],所以OptionWriter[Nothing]需要一个JsonWriter[Nothing]。如果你试试 Json.toJson(Some(1)) 是一样的,没有 JsonWriter[Int].

另一方面,Json.toJson(None:Option[String]) 有效,因为 OptionWriter[String] 可以得到 JsonWriter[String]。