4

2 つのユーティリティ メソッドを次のように宣言しました。implicit

class MyClass { ... }
object MyClass {
   implicit def finish: MyClass[Any,Nothing,Unit] = finish(());
   implicit def finish[R](result: R): MyClass[Any,Nothing,R] = ...
}

コンパイラの警告が表示されます:

パラメーター化されたオーバーロードされた暗黙的なメソッドは、ビューの境界として表示されません

この警告はどういう意味ですか?

4

1 に答える 1

4

ここで「パラメータ化された」は、実際には「型がパラメータ化された」はずです。または、他の言葉では、警告は、オーバーロードされた(同じ名前の他のメソッドがあります) とgenericの両方である暗黙的な変換を定義したため、メソッドを暗黙的なビューとして実際に使用することはできませんが、使用することはできます。単なる値を暗黙的に変換します。例を使って違いを説明しようとします:

class MyClass
object MyClass {
   implicit def finish: MyClass = null
   implicit def finish[R](result: R): MyClass = null
}

val a: Int = 123
val b: MyClass = a // Compiles fine: implicit conversion properly applied

def foo[R<%MyClass]( r: R ) {}
foo( 123 ) // Error: No implicit view available from Int => Test.MyClass

上記のコード スニペットでは、a(型のInt) は暗黙的に に変換されるMyClassため、暗黙的な変換は期待どおりに機能します。

ただし、興味深いのはfooメソッドにあります。にバインドされたビューで宣言されていますMyClassfooつまり、暗黙的に に変換可能な任意の値に渡すことができるはずですMyClass。しかし、ここではコンパイルに失敗します。これは、コンパイラが警告していたこのエラーです。finishそして確かに、 (型パラメーターを取らないもの)の最初のオーバーロードをコメント アウトするか、バージョンの名前を変更してオーバーロードにならないようにすると (たとえば、バージョンの 1 つを に変更するとfinish2)、コンパイル エラーはなくなります。 .

最初のケース (直接の暗黙的な変換) と 2 番目のケース (ビュー バインドを使用したメソッドの呼び出し) で、一方は正常にコンパイルできるが、もう一方はコンパイルできないという違いについて疑問に思っている場合、キー ポイントは、ビュー バインドが暗黙的な関数値を渡す必要があります。

それはそう、

def foo[R<%MyClass]( r: R )

と同じです

def foo[R]( r: R )( implicit conv: R => MyClass)

したがって、 を呼び出すときfoo、コンパイラは適切な暗黙的な変換を見つけるだけでなく、暗黙的な変換メソッド (2 番目のfinishオーバーロード) を関数インスタンスにプロモートし、それを暗黙的に に渡す必要がありますfoo

これは、型パラメーター化されたメソッドとオーバーロードされたメソッドの場合に、コンパイラーが (何らかの理由で) 方法を知らないこのプロモーションだと思います。これは純粋な憶測ですが、これは単なる実装上の制限であると確信しています。これは非常に実行可能ですが、十分に重要であるとは見なされないほど実装上の問題が発生します (結局のところ、暗黙の名前を変更するだけで修正できます)。変換方法)。

補足として、警告は scala 2.10 では (デフォルトで) 発行されません (scala での型クラスの使用の急増により、ノイズが多すぎると見なされました) が、実際の問題は残り、 への呼び出しはfoo依然としてコンパイルに失敗します。

于 2013-03-04T09:25:31.037 に答える