質問

過負荷時にメソッドの分散を理解するのが少し問題があります。

これは返品タイプの共分散のために完全に機能しますが

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
}

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

よろしく、ライチョ

役に立ちましたか?

解決

ここでは2つのことが起こっています。

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

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

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

この関数は、入力タイプが対照的になります。 (しかし、それは機能すると言う価値があります パラメーター化することはできません また、私はのインスタンスを持っていなければならなかったと言う価値があります Foo また FooTest の関数オブジェクトを取得するため tester 方法。もちろん、これは最初の観察から続きます!)

関数はオブジェクトです、 オーバーライドすることはできません それは意味がありません。メソッドはオーバーライドできます。ただし、上で述べているように、オーバーライドはメソッドのパラメータータイプでは多型ではありません。したがって、例:

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 ある関数が別の機能のサブタイプであることの意味を定義します(したがって 割り当て可能 特定のタイプの参照)。
  • メソッドはサブクラスでオーバーライドでき、言語仕様は、そのようなオーバーライドがいつ行われるかのルールの概要を説明します。

他のヒント

仕様の関連するスニペット:

メソッドタイプ

メソッドタイプは内部で示されます (Ps)U 、 どこ (Ps) パラメーター名とタイプのシーケンスです (p1 :T1,...,pn :Tn) いくつかのための n≥0U (値または方法)タイプです。このタイプは、名前が付けられた引数を取得する名前のメソッドを表します p1, ..., pn タイプの T1,...,Tn そして、それはタイプの結果を返します U.

メソッドタイプは、値のタイプとして存在しません。メソッド名が値として使用される場合、そのタイプは対応する関数タイプ(§6.26)に暗黙的に変換されます。

オーバーライド

メンバー M クラスの C それ マッチ (§5.1.3)非プライベートメンバー M′ のベースクラスの C そのメンバーを無効にすると言われています。この場合、オーバーライドメンバーの結合 M しなければならない サブセム (§3.5.2)オーバーライドされたメンバーの結合 M′.

適合

もしも Ti ≡ Ti′ にとって i = 1, ..., nU に適合します U′ 次に、メソッドタイプ (p1 : T1,...,pn :Tn)U に適合します (p1′ :T1′,...,pn′ :Tn′)U′.

包着

いくつかの複合タイプのクラスタイプの宣言または定義 C いくつかの複合タイプまたはクラスタイプで同じ名前の別の宣言を包含する C′ 、次のいずれかが保持されている場合。

  • タイプtの名前xを定義する値宣言または定義は、定義する値またはメソッド宣言を包含する x タイプ付き T′, 、 提供された T <: T′.

リターンタイプをサブタイプにオーバーライドして変更できますが、引数のスーパータイプを受け入れると代替原則を満たすことができますが、それは許可されません(これはJavaと同じです)。名前、異なる引数数とタイプ)とあなたの方法は過負荷と考慮されます。これは主にJVMの互換性と合理的な仕様を持っていることの問題だと思います。過負荷はすでにScala仕様をかなり複雑にします。 Overridenメソッドを変更した署名でオーバーロードされた方法にルーティングするだけで、十分に優れている可能性があります。

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

2番目の例では、の署名です tester()Test 宣言します Fasel 議論ですが、オーバードリデンの署名があります FooTest tester() で宣言されています Bla 議論として。以来 Fasel のサブタイプです Bla 彼らによって extends階層これはおそらく間違っています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top