【发布时间】:2013-11-17 19:17:31
【问题描述】:
我正在尝试使用 Scala 中的 typeclass 模式来标记所有有效的 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 }
}
但我不知道如何使用它。哈普?
【问题讨论】:
-
查看this question 了解否定技巧的演练。我最终得到了一个通用的“Not[_]”类型类。查看答案了解更多详情。
标签: scala type-systems shapeless