我正在尝试使用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
的重复含义。我看到Miles Sabin使用了一个技巧:
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 }
}
但我无法弄清楚如何使用它。 HALP?
答案 0 :(得分:2)
好的,感谢Scala IRC频道的一些帮助,我发现创建了LowPriority implicits来解决这个问题。
我用它来修复它:
sealed class SafeForPublic[-T]
trait LowPriorityImplicits {
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]
}
object Implicits extends LowPriorityImplicits {
implicit object NothingOk extends SafeForPublic[Nothing]
}
import Implicits._
def boxed[T : SafeForPublic](t: Option[T]) = println("woohoo!")
boxed(None) // compiles! \o/