【问题标题】:How to trick Scala to not find duplicate implicits for Nothing如何欺骗 Scala 不为 Nothing 找到重复的隐式
【发布时间】: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]

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

但我不知道如何使用它。哈普?

【问题讨论】:

  • 查看this question 了解否定技巧的演练。我最终得到了一个通用的“Not[_]”类型类。查看答案了解更多详情。

标签: scala type-systems shapeless


【解决方案1】:

好的,感谢 Scala IRC 频道的一些帮助,我发现 LowPriority 隐式是为了解决这个问题而创建的。

我用这个来修复它:

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/

【讨论】:

  • 您能解释一下为什么这个解决方案有效吗?我猜LowPriorityImplicits 这个名字并没有什么特别之处,但从你的回答中也不清楚。
  • @ziggystar 这是隐式继承的特殊规则,查看scala-lang.org/files/archive/spec/2.11/…
猜你喜欢
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
相关资源
最近更新 更多