6

この例のセットアップ (Scala 2.10.3):

trait S[A]
trait T[A]
implicit class X[A : S](a: A) { def foo() { } }
implicit class Y[A : T](a: A) { def foo() { } }
implicit object I extends S[String]

これはコンパイルされます:

new X("").foo()

これはしません:

new Y("").foo()

暗黙的な がないためT[String]です。

could not find implicit value for evidence parameter of type T[String]
              new Y("").foo()
              ^

したがって、scalac は からStringへの暗黙的な変換を明確に適用できると思いXます。

"".foo()

しかし、代わりに次のようになります。

type mismatch;
 found   : String("")
 required: ?{def foo: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method X of type [A](a: A)(implicit evidence$1: S[A])X[A]
 and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A]
 are possible conversion functions from String("") to ?{def foo: ?}
              "".foo()
              ^

これは意図的なものですか?scalac は、候補を列挙するときに各変換が実際に機能するかどうかを考慮する必要はありませんか?

4

1 に答える 1

4

私の非学術的な見解は、暗黙的は、機能するように見えるたびに機能することを意図したものではなく、設計上であるというものです。そうしないと、暗黙の地獄に簡単に陥ってしまうので、それは良い考えだと思います。暗黙的な変換の層をさらに追加することで、例を拡張できます。コードを見ただけでは、実際にどの関数が呼び出されているかを判断するのは難しいでしょう。明確に定義されたルールがありますが、何が起こっているのかがコードから明らかでなければ、機能しないことを単純に覚えています。

あなたのコードは、非曖昧性ルールを破ることにつながる1つずつルールを破っていると思います。は単なる構文糖衣であり、次のように書き換えることができます。A : S

implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } }
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } }

「第 2」の暗黙的レベル (メソッド引数e) の解決がなければ、両方のクラスXYコンパイラーは同じように見えるため、あいまいになります。リンクされたドキュメントにあるように、「健全性のために、コンパイラは、別の暗黙的な変換を既に試行しているときに、それ以上の暗黙的な変換を挿入しません。

于 2014-02-15T09:23:15.727 に答える