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"
還值得一提的是,這模式並不侷限於兩層,但您可以創建特徵層次結構,並在其中包含從更具體到更通用的隱式定義,繼承樹。