6

オーバーロード時のメソッドの分散を理解するのに少し問題があります。

これは、リターンタイプの共分散のために完全に機能しますが

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(): Bla = new Bla
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(): Fasel = new Fasel                                      
}

関数のパラメータータイプが反変であっても、これは失敗します。

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(a: Fasel): Bla = new Bla                                           
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(a: Bla): Fasel = new Fasel
}

ここで何が間違っているのですか?ポインタはありますか?

よろしく、raichoo

4

4 に答える 4

12

ここでは次の 2 つのことが行われています。

  1. 関数とメソッドは同じものではありません
  2. メソッドは、パラメーターの型が多態的ではありません

あなたのtesterメソッドはメソッドではなく、Function1 . アンダースコア構文を使用して、関数に持ち上げることができます。

val f = (new FooTest[String]).tester _ // Fasel => Bla

この関数は、その入力型が反変になります。(ただし、関数はパラメーター化できないことは言うまでもありません。また、メソッドの関数オブジェクトを取得するには、Fooまたはのインスタンスが必要であると言う価値もあります。これはもちろん、最初の観察から導かれます!)FooTesttester

関数はオブジェクトであり、意味がないためオーバーライドできません。メソッドはオーバーライドできます。ただし、上で述べたように、オーバーライドはメソッドのパラメーター型では多態的ではありません。たとえば、次のようになります。

class A {
  def foo(a : Any) = println("A: " + a)
}

class B extends A {
  override def foo(s : String) = println("B " + s) //will not compile!
}

上記の例の 2 つのメソッドは、2 つの別個のメソッドです。動的ディスパッチは、メソッド ターゲット (つまり、呼び出されているオブジェクト) でのみ機能します。

上記の例では、宣言を削除するoverrideと、コードはコンパイルされます。以下を実行する場合:

(new B).foo(1)   //prints A 1
(new B).foo("s") //prints B s

これは、両方のメソッドが呼び出されfooていますが、完全に異なるメソッドであるためです (つまり、オーバーロード fooしたのではなく、オーバーライドしたためです)。メソッドの引数 (それらの型を含む) は、そのメソッドの一意の名前の一部を形成するということとして最もよく理解されています。名前がまったく同じ場合にのみ、1 つのメソッドが別のメソッドをオーバーライドします。


基本的に、あなたは質問で2つの別々の関連のないものを混同しています。明確にするためにそれらを下に置きます。

  • 上のバリアンス アノテーションFunction1は、ある関数が別の関数のサブタイプである (したがって、特定の型の参照に割り当て可能である) ことの意味を定義します。
  • メソッドはサブクラスでオーバーライドできます。言語仕様では、そのようなオーバーライドがいつ行われるかについてのルールが概説されています。
于 2010-11-28T14:08:24.423 に答える
4
于 2010-11-28T15:54:51.687 に答える
0

戻り値の型をオーバーライドしてサブタイプに変更することはできますが、引数にスーパータイプを受け入れることは置換の原則を満たしますが、許可されません (これは Java と同様です)。名前、異なる引数の数と型) と、メソッドはオーバーロードと見なされます。これは主に JVM の互換性と妥当な仕様の問題だと思います。オーバーロードは既に scala 仕様をかなり複雑にしています。オーバーライドされたメソッドを、署名が変更されたオーバーロードされたメソッドに単純にルーティングするだけで十分な場合があります。

class FooTest[A] extends Test[A] {
   override def test(a: Fasel) : Fasel = test(a.asInstanceOf[Bla])
   def test(a: Bla) : Fasel = new Fasel
}

できることは、型パラメーターを反変にすることです。提供されるのは、反変の位置にのみ表示されます (単純化、結果の型としてではなく、引数の型として表示されます) が、それはまったく異なります。

trait Test[-A] {
  // note the - before A. 
  // You might want to constraint with -A >: Fasel
  def tester(a: A) : Bla = new Bla
}

class FooTest extends Test[Bla] {
  override def tester(a: Bla): Fasel = new Fasel
}

val testOfBla: Test[Bla] = new FooTest
val testOfFasel: Test[Fasel] = testOfBla 
  // you can assign a Test[Bla] to a test[Fasel] because of the -A
于 2010-11-28T14:36:04.050 に答える
-1

2番目の例では、 in の署名がtester()引数をTest宣言していFaselますが、オーバーライドされた署名では、 as 引数FooTest tester()で宣言されています。は階層によるのサブタイプであるBlaため、これはおそらく間違っています。FaselBlaextend

于 2010-11-28T14:00:35.927 に答える