Я пытаюсь использовать шаблон класса типов в Scala, чтобы пометить все допустимые сериализуемые типы API, чтобы мы могли обеспечить безопасность во время компиляции в отношении того, что мы сериализуем. Наша базовая библиотека принимает AnyRef
, что может привести к странным ошибкам, если тип явно не объявляется перед его сериализацией.
Мы разрешаем отправку общедоступной модели, итерации общедоступных моделей, варианта общедоступной модели или единицы.
trait PublicModel
case class UserModel(name: String) extends PublicModel
sealed class SafeForPublic[-T]
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
Этот метод хорошо работает для всего, кроме методов, в которых тип параметра является опцией. Это связано с тем, что None
является Option[Nothing]
, поэтому T = Nothing
говорит компилятору искать неявный объект типа SafeForPublic[Nothing]
, и он найдет как SafeForPublic[PublicModel]
, так и SafeForPublic[Iterable[PublicModel]]
.
def boxed[T : SafeForPublic](t: Option[T]) = println("wooohoo!")
boxed(Some(None)) // works
boxed(Some(1)) // doesn't compile. Int is not a valid serializable model.
boxed(Some({})) // works
boxed(Some(UserModel("ok"))) // works
boxed(Some(Seq(UserModel("ok")))) // works
boxed(None) // doesn't compile, duplicate implicits ><
Любая идея, как я могу обмануть компилятор, чтобы он не находил повторяющиеся имплициты для Nothing
. Я видел, как у Майлза Сабина был трюк, использующий:
sealed trait NotNothing[A]{
type B
}
object NotNothing {
implicit val nothing = new NotNothing[Nothing]{ type B = Any }
implicit def notNothing[A] = new NotNothing[A]{ type B = A }
}
Но я не мог понять, как его использовать. Халп?