2015-11-05 1 views

Antwort

13

Dieses Muster ermöglicht es Ihnen, eine Hierarchie von Implikaten zu haben, die Mehrdeutigkeitsfehler durch den Compiler vermeidet und eine Möglichkeit bietet, diese zu priorisieren. Als Beispiel betrachten wir die folgenden:

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 

Der Fehler, den Sie in der letzten Zeile erhalten ist:

<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) 

Dies würde nicht kompilieren, da die implizite Auflösung Mehrdeutigkeit finden; In diesem Fall ist es ein wenig künstlich, dass wir den String Fall unter Verwendung des impliziten Beweises definieren, um die Mehrdeutigkeit auszulösen, wenn wir sie einfach als implicit def specialForString: MyTypeclass[String] = ... definieren und keine Mehrdeutigkeit haben könnten. Aber es gibt Fälle, in denen Sie auf anderen impliziten Parametern abhängen, wenn implizite Instanzen definieren und mit Hilfe der niedrigen Priorität Mustern können Sie es wie folgt schreiben und es hat gut funktionieren:

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" 

Es ist auch erwähnenswert, dass diese Das Muster ist nicht auf zwei Ebenen beschränkt, sondern Sie können eine Hierarchie von Merkmalen erstellen und darin implizite Definitionen enthalten, die von einer spezifischeren zur allgemeineren gehen, die den Vererbungsbaum hinaufführt.

Verwandte Themen