Frage

Ich bin ein kleines Problem mit den Methoden verstehe Varianz bei Überlastung.

Während diese perfekt funktioniert aufgrund Kovarianz im Rückgabetyp

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                                      
}

diese ausfällt, obwohl Funktionen kontra in ihrer Parametertypen.

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
}

Was bekomme ich hier falsch? Alle Zeiger?

Viele Grüße, raichoo

War es hilfreich?

Lösung

Es gibt zwei Dinge, die sich hier:

  1. Eine Funktion und ein Verfahren ist nicht dasselbe
  2. Methoden nicht polymorph sind in ihren Parametern Typen

Ihre tester Methode ist eine Methode, keine Function1 . Es kann in eine Funktion mit der Unterstrich-Syntax angehoben werden:

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

Diese Funktion ist kontravarianten in seinem Eingangstyp. (Es lohnt sich sagen jedoch, dass Funktionen nicht parametrierbar und auch wert, dass ich hatte eine Instanz von Foo oder FooTest haben, um ein Funktionsobjekt für die tester Methode zu erhalten. Das ist natürlich folgt von der ersten Beobachtung!)

Eine Funktion ist ein Objekt, es kann nicht außer Kraft gesetzt , wie das macht keinen Sinn. Methoden außer Kraft gesetzt werden können. Aber, wie ich oben gesagt, ist die übergeordnete nicht polymorph in den Parametertyp Methode. So zum Beispiel:

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

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

Die beiden Verfahren, die in meinem oben genannten Beispiel sind zwei verschiedene Methoden. Dynamische Dispatch funktioniert nur auf dem Ziel-Methode (das heißt das Objekt, auf dem sie aufgerufen wird)

In dem obigen Beispiel, wenn Sie die override Erklärung entfernen, wird der Code kompiliert. Wenn Sie die folgende ausführen:

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

Das ist, weil, obwohl beide Methoden foo genannt werden, sind sie völlig unterschiedliche Methoden (das heißt ich habe überladene foo, nicht außer Kraft gesetzt it). Es ist am besten verstanden als dass ein Verfahren Argument (inkl deren Typen) Teil dieses Verfahrens ist einzigartig name . Eine Methode überschreibt andere nur, wenn sie genau das gleiche name .


Im Wesentlichen haben Sie verwirrt, was sind zwei getrennt und un bezogenen die Dinge in Ihrer Frage, die ich für Klarheit hinstellen wird:

  • Die Varianz Annotationen auf Function1 definieren, was es bedeutet, für eine Funktion ein Untertyp eines anderen zu sein (und damit zuweisbaren zu einem Referenz eines bestimmten Typs).
  • Methoden können auf Unterklassen außer Kraft gesetzt werden und die Sprachspezifikation Umrissen Regeln dafür, wann eine solche übergeordnete stattfindet.

Andere Tipps

Die entsprechenden Schnipsel der Spezifikation:

Method Typen

  

Verfahren Typ bezeichnet wird intern als (Ps)U, wo (Ps) ist eine Folge von Parameternamen und -arten für einige (p1 :T1,...,pn :Tn) n≥0 und U ist ein (Wert oder Methode) Typ. Diese Art stellt genannten Methoden, die Argumente genannt p1, ..., pn von Typen T1,...,Tn und diese Rückkehr ein Resultat vom Typ U nehmen.

     

Methodentypen existieren nicht als Arten von Werten. Wenn ein Methodenname als ein Wert verwendet wird, wird sein Typ implizit in einen entsprechenden Funktionstyp umgewandelt (§6.26).

Übergeordnete

  

Ein Mitglied M die Klasse C dass Streichhölzer (§5.1.3) ein nicht-privates Mitglied M′ eine Basisklasse von C gesagt, dass Mitglied außer Kraft setzen. In diesem Fall wird die übergeordnete Mitglied M muss die Bindung subsume (§3.5.2) die Bindung des überschriebenen Mitglied M′.

Conformance

  

Wenn Ti ≡ Ti′ für i = 1, ..., n und U Konform U′ die Methode Typ (p1 : T1,...,pn :Tn)U Konform (p1′ :T1′,...,pn′ :Tn′)U′ dann.

subsumiert

  

Eine Erklärung oder Definition in irgendeiner Verbindung Art des Klassentyp C subsumiert eine weitere Erklärung des gleichen Namen in irgendeiner Verbindung Typ oder Klassentyp C′, wenn eines der folgenden gilt.

     
      
  • Ein Wert Erklärung oder Definition, die definiert, ein Name x mit Typ T einen Wert oder Methodendeklaration subsumiert, die definiert x mit Typ T′, vorausgesetzt T <: T′.
  •   

Sie können außer Kraft setzen und den Rückgabetyp auf einen Subtyp ändern, aber während geordneter Typ für Argument akzeptieren, das Substitutionsprinzip genügen würde, ist es nicht erlaubt (dies ist ebenso wie in Java) Der Grund dafür ist, dass Sie auch Methoden überlasten (mehrere Methoden mit dem gleichen Namen, zählen und Typen unterschiedliche Argumente) und Ihre Methode wird eine Überlastung considerered werden. Ich denke, dies ist in erster Linie eine Frage der JVM-Kompatibilität und eine angemessene spec hat. Eine Überlastung macht bereits die scala spec ziemlich kompliziert. Einfach Routing könnten die überschriebene Methode, um die überlasteten eine mit der geänderten Signatur gut genug sein:

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

Was Sie tun können, ist eine Art Parameter kontra machen, in erscheint vorgesehen nur in kontra Position (vereinfacht, erscheint als Argument Typ und nicht als Ergebnistyp), aber es ist ganz anders:

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

Nun, in Ihrem zweiten Beispiel die Unterschrift von tester() in Test erklärt ein Fasel Argument aber mit der überschriebenen Signatur von FooTest tester() ist mit einem Bla als Argument erklärt. Da Fasel ein Subtyp von Bla durch ihren extends ist Hierarchie dies wahrscheinlich falsch ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top