3
比方說我們想用類型類來實現漂亮的印刷:斯卡拉:implicits,子類和成員類型
trait Printer[T] {def print(t: T)}
與整數默認實現:我們要
implicit object IntPrinter extends Printer[Int] {
override def print(i : Int): Unit = println(i)
}
我們的具體類型打印如下:
trait Foo {
type K
val k: K
}
class IntFoo extends Foo {
override type K = Int
override val k = 123
}
很酷。現在我想建立所有FOOS打印機可打印Ks的
implicit def fooPrinter[FP <: Foo](implicit ev: Printer[FP#K]): Printer[FP] =
new Printer[FP] {
override def print(f: FP): Unit = {
Predef.print("Foo: ")
ev.print(f.k)
}
}
讓檢查implicits得到解決:
def main(args: Array[String]) {
implicitly[Printer[Int]]
implicitly[Printer[IntFoo]]
}
scalac 2.11.2說:
diverging implicit expansion for type Sandbox.Printer[Int]
starting with method fooPrinter in object Sandbox
implicitly[Printer[Int]]
whaat?
OK,讓我們重寫fooPrinter:
implicit def fooPrinter[KP, FP <: Foo {type K = KP}](implicit ev: Printer[KP]) =
new Printer[FP] {
override def print(f: FP): Unit = {
Predef.print("Foo: ")
ev.print(f.k)
}
}
這部作品在2.11,但什麼是與第一種方法的問題? 不幸的是,我們在2.10,第二個解決方案仍然無法正常工作。它編譯直到我們添加像
implicit object StringPrinter extends Printer[String] {
override def print(s : String): Unit = println(s)
}
一個更森達打印機,它神祕地打破打印機[IntFoo]隱:
could not find implicit value for parameter e:
Sandbox.Printer[Sandbox.IntFoo]
編譯器錯誤?
移動它修復fooPrinter對2.11的第一個定義(並導致對2.10真是奇怪的錯誤)。如果訂單不同,他們爲什麼會衝突? – eprst 2014-10-02 18:09:56
我對隱含的看法是,如果甚至有一點疑問,那麼它根本不起作用。它是由設計偏執狂,以便它不會意外解決你可能不期望的事情......但是這並不能回答你的問題。我會假設編譯器已經發現了一個隱含的定義Printer [FP],它可能僅僅通過查看它的返回值就可以返回Printer [Int]。此時它可能不檢查FP <:Foo限制。然後它爲Printer [Int]找到另一個隱式定義。這就是錯誤。但那只是我的理論。 – 2014-10-02 18:24:22
隱式分辨率如此脆弱的另一個原因是編譯速度。正如你可以想象的那樣,如果它真的試圖評估所有可能的隱式定義,它可能會成爲指數回溯惡夢。但透明度可能更重要。 – 2014-10-02 18:28:28