Неявный поиск для 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
(который является подтипом всего)