2015-11-05 11 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) 

暗黙的な解決には曖昧さがありますので、これはコンパイルされません。この場合、暗黙の証拠を使用してimplicit def specialForString: MyTypeclass[String] = ...と定義し、あいまい性がない場合には、あいまいさを引き起こすために、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" 

をまた、このことは注目に値する。しかし、暗黙のインスタンスを定義し、次のようにあなたはそれを書くことができますし、それが正常に動作している優先度の低いパターンを使用しているときに、他の暗黙のパラメータに依存する必要がある場合がありますパターンは2つのレイヤーに限定されませんが、特質の階層を作成し、より具体的なものからより一般的なものへの継承ツリーへの暗黙の定義を持つことができます。

関連する問題