如何欺骗Scala找不到Nothing的重复含义

时间:2013-11-17 19:17:31

标签: scala type-systems shapeless

我正在尝试使用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]

此方法适用于除参数类型为选项的方法之外的所有内容。这是因为NoneOption[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?

1 个答案:

答案 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/