Mehrdeutige Referenz auf überladene definition - Einer gegen Zwei Parameter
Angesichts der folgenden Begleiter-Objekt mit überladenen Versionen von apply
:
object List {
def apply[T](): List[T] = new Nil
def apply[T](x1: T): List[T] = new Cons(x1, new Nil)
def apply[T](x1: T, x2: T): List[T] = new Cons(x1, new Cons(x2, new Nil))
def apply[T](elems: T*): List[T] =
elems.foldRight(List[T])((elem, l) => new Cons(elem, l))
}
Und die beiden Instanziierungen
List(1) //Error - Ambiguity
List('a', 'b') //Works fine
scalac beschwert sich über die ersten Instanziierung (mehrdeutigen Verweis auf überladene definition), da sowohl die Einzel-als argument und die varargs-Methode sind ebenso bestimmte.
Suche stackoverflow habe ich gefunden, dass es möglich ist,Kraft das einzige argument der Methode. List[Int](1)
wird der compiler verwenden def apply[T](x1: T)
.
Meine Frage ist, warum hat die zweite Instanziierung match def apply[T](x1: T, x2: T)
ohne zusätzliche "hints"? In anderen Worten, warum die beiden argument-Methode mehr bestimmten als die varargs-Methode, wo das einzige argument der Methode nicht?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ihre Frage zu beantworten, müssen wir einen Blick auf, was passiert, wenn der Scala-compiler zu erbringen hat, überlastung Auflösung. Dies ist beschrieben in SLS 6.23.3 (für Scala 2.9).
Nehmen wir eine etwas einfachere version Ihrer Beispiel:
Und Blick auf diese drei Aufrufe:
Lasst uns mit dem ersten beginnen. Zuerst sucht der compiler in der Form jedes argument, das ist ein Typ, der beschreibt, im Grunde, wenn das argument ist ein Wert oder eine Funktion. Hier keine Schwierigkeit,
1
ist eine ganz normale, langweilig Wert und seine Form ist der TypNothing
.Jetzt hat es ein einziges argument
1
TypNothing
und findet alle alternativen, die für ihn anwendbar sind. Es findet zwei von Ihnen:apply[T](x1: T)
: man nimmt ein einzelnes argument des unbounded Typ, so kann ein argument vom TypNothing
,apply[T](elems: T*)
: es kann angewendet werden, um eine beliebige Anzahl (0
im Lieferumfang enthalten) der Argumente des gleichen unbounded Typ, so kann ein einzelnes element vom TypNothing
.Gab es nur ein, er würde dort anhalten und wählen, dass man.
Der zweite Schritt ist gleich wie oben, außer dieser Zeit, es Typen, die jedes argument mit einer unbestimmten erwarteten Typ. Hier im Grunde sieht es bei den beiden alternativen Links und findet heraus, ob Sie anwendbar sind auf das argument
1
TypA <: Int
. Kein Glück, Sie beide sind.Wenn Sie waren zwei ändern
apply[T](x1: T)
zuapply(x1: String)
und lassen Sie die anderen allein, hier gibt es nur eine anwendbare alternative Links, und es würde gelingen und stoppen.Dann der compiler berechnet die
relative weight
jeder Links-alternative über einander. Die SLS-Staaten, dieZu diesem Zeitpunkt muss es eine alternative, die eine höhere Punktzahl als alle anderen, oder gibt es eine Mehrdeutigkeit Fehler. Wir ignorieren das "definiert" Teil, definiert sind Sie in der gleichen Stelle.
A
ist so spezifisch wieC
da kann man immer anrufenC
mit dem einzigen argument vonA
,C
ist so spezifisch wieA
weil der Typ-Inferenz: Sie können immer AufrufA
mit dem argument derC
seitA
kann alles (der parameter Typ abgeleitet werden kann, auf das, was wir wollen).C
's-Parameter ist als eineSeq[A]
soT
abgeleitet, wieSeq[A]
imA
und es kann sich so nennen. SoC
ist so spezifisch wieA
.Dies kann gesehen werden, wenn Sie ändern
A
zuapply[T <: Int](x: T)
: es geht den ganzen Weg zu suchen, für die bestimmte, aber dieses mal Typ-Inferenz, kann nicht einen Weg finden, umA
geltendenC
's argument (einSeq
) denn es ist nicht ein Subtyp vonInt
, soA
spezifischer ist. Natürlich, das gleiche passiert, wenn Sie ändernA
zuapply(x: Int)
, Typ-Inferenz, kann nicht einmal etwas tun.Dies erklärt auch, warum
Test[Int](1)
gelingt, ruft das eine argument-version. Die letzten beiden alternativen sind identisch, aberA
's type-parameter gebunden wurde, umInt
- und Typ-Inferenz, kann es nicht ändern, um zu passenC
's argument mehr.Schließlich, die Anwendung der gleichen Logik gibt, warum
Test(1,2)
gut funktioniert:B
ist so spezifisch wieC
: Sie können immer AufrufC
mitB
's Argumente,C
ist nicht so spezifisch wieB
: Nein Menge von Typ-Inferenz wird verwalten zu passen, einen einzelnenSeq
in eine Methode, die zwei Parameter.So
apply[T](x1: T, x2: T)
spezifischer ist und keine Fehler vorhanden sind.Grundsätzlich für eine var-arg und eine normale Methode, um zu produzieren, eine Zweideutigkeit, Sie werden Sie brauchen, um die gleiche Anzahl von Argumenten und einen trick, mit dem Typ-Inferenz, die auf (mindestens) das Letzte argument:
Oder
Und so weiter...
Bearbeiten: ich war mir nicht sicher zuerst, ob der parameter wiederholt gesehen wurde, als
Seq[A]
oder eineTupleX[...]
bei der Suche nach der Besonderheit. Es ist definitiv nicht ein Tupel, und auto-tupling hat nichts zu tun mit dieser Sache.Fester stelligkeit Methode wird immer mehr spezifisch als die var-Dimension.
f(P1, P2)
gilt nicht für(a, b, c, ...)
ist, wie man sich denken kannf(P*)
.Umgekehrt, obwohl
f(P*)
nimmt die Formf(p1,..,pn)
für die Zwecke der Anwendbarkeit auf die N Argumente. Also es gilt immer und ist nicht so spezifisch wie die Feste stelligkeit Methode.So, dass ist der übliche Grund, Ihre
f(a,b)
ist spezifischer alsf(P*)
.Für die eine-arg-Fall, es hängt davon ab, was Sie abholen für die Typ-param.
f[A](a: A)
gilt für(a, b, ...)
von tupling und wobei Ein als ein Tupel.Sagen = Int, dann ist das offensichtlich Ein nicht zu genommen werden, als ein Tupel.
Probe Verwirrung über die var-Dimension und wie wirkt Besonderheit:
https://issues.scala-lang.org/browse/SI-4728
Möchten Sie vielleicht Stelle diese Frage auf stackoverload.com die Seite, wo die überlastung Spezialisten sammeln. Ihr browser umgeleitet werden kann, um overloading-is-evil.com.
Foo(x1: T)
,T
könnte einTuple
, Tupel und varargs sind gleichermaßen spezifisch, das ist, warum ich brauchen, um anzudeuten, der compiler, dassT
ist nicht ein Tupel Recht?