9
在查看一些Scala库的源代码时, shapeless,我经常发现名为LowPriorityImplicits
的特征。说明在Scala类型级编程中使用的`LowPriorityImplicits`模式
你能解释一下这种模式吗?解决的问题是什么,该模式如何解决它?
在查看一些Scala库的源代码时, shapeless,我经常发现名为LowPriorityImplicits
的特征。说明在Scala类型级编程中使用的`LowPriorityImplicits`模式
你能解释一下这种模式吗?解决的问题是什么,该模式如何解决它?
该模式允许您具有隐含层次结构,避免编译器产生与模糊相关的错误,并提供一种优先考虑它们的方式。例如,考虑以下几点:
trait MyTypeclass[T] { def foo: String }
object MyTypeclass {
implicit def anyCanBeMyTC[T]: MyTypeclass[T] = new MyTypeclass[T] {
val foo = "any"
}
implicit def specialForString[T](implicit ev: T <:< String): MyTypeclass[T] = new MyTypeclass[T] {
val foo = "string"
}
}
println(implicitly[MyTypeclass[Int]].foo) // Prints "any"
println(implicitly[MyTypeclass[Boolean]].foo) // Prints "any"
println(implicitly[MyTypeclass[String]].foo) // Compilation error
您在最后一行得到的错误是:
<console>:25: error: ambiguous implicit values:
both method anyCanBeMyTC in object MyTypeclass of type [T]=> MyTypeclass[T]
and method specialForString in object MyTypeclass of type [T](implicit ev: <: <[T,String])MyTypeclass[T]
match expected type MyTypeclass[String]
println(implicitly[MyTypeclass[String]].foo)
这不会编译,因为隐式解析,就会发现不确定性;在这种情况下,这有点虚构,因为我们使用隐式证据定义String
案例,以便在我们可以将其定义为implicit def specialForString: MyTypeclass[String] = ...
且没有任何歧义时触发歧义。但也有在那里你定义隐含的实例,并使用低优先级的模式,你可以写成如下它,并将它很好地工作时,需要依赖于其他隐参数情况:
trait MyTypeclass[T] { def foo: String }
trait LowPriorityInstances {
implicit def anyCanBeMyTC[T]: MyTypeclass[T] = new MyTypeclass[T] {
val foo = "any"
}
}
object MyTypeclass extends LowPriorityInstances {
implicit def specialForString[T](implicit ev: T <:< String): MyTypeclass[T] = new MyTypeclass[T] {
val foo = "string"
}
}
println(implicitly[MyTypeclass[Int]].foo) // Prints "any"
println(implicitly[MyTypeclass[Boolean]].foo) // Prints "any"
println(implicitly[MyTypeclass[String]].foo) // Prints "string"
还值得一提的是,这模式并不局限于两层,但您可以创建特征层次结构,并在其中包含从更具体到更通用的隐式定义,继承树。