2015-11-05 25 views

回答

13

該模式允許您具有隱含層次結構,避免編譯器產生與模糊相關的錯誤,並提供一種優先考慮它們的方式。例如,考慮以下幾點:

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" 

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