Неявный поиск для Typeclass of None не совместим с 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

2 ответа

Решение

None, если вы не говорите ничего другого, это Option[Nothing], так OptionWriter[Nothing] нужен JsonWriter[Nothing], Если вы попытаетесь Json.toJson(Some(1)) то же самое, нет JsonWriter[Int],

С другой стороны, Json.toJson(None:Option[String]) работает, потому что OptionWriter[String] может получить JsonWriter[String].

Я думаю, что это связано с тем, что

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

если вы выполните одно из следующих действий, оно будет работать

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

Обратите внимание, что второй использует тип приписывания, чтобы поставить лицо, так сказать, на Nothing (который является подтипом всего)

Другие вопросы по тегам