2012-10-28 7 views
8

ich die folgenden Fehler:Fehler: polymorpher Ausdruck mit Standardargumenten

trait Foo[A] 
class Bar[A](set: Set[Foo[A]] = Set.empty) 

Diese

<console>:8: error: polymorphic expression cannot be instantiated to expected type; 
found : [A]scala.collection.immutable.Set[A] 
required: Set[Foo[?]] 
     class Bar[A](set: Set[Foo[A]] = Set.empty) 
             ^

Es liefert, ist sehr ärgerlich, dass ich die Typ-Parameter in Set.empty wiederholen. Warum schlägt die Typinferenz mit diesem Standardargument fehl? Die folgenden Werke:

class Bar[A](set: Set[Foo[A]] = { Set.empty: Set[Foo[A]] }) 

Bitte beachten Sie, dass dies nichts mit Set insbesondere zu tun hat:

case class Hallo[A]() 
class Bar[A](hallo: Hallo[A] = Hallo.apply) // nope 

Seltsamer nicht nur das funktioniert:

class Bar[A](hallo: Hallo[A] = Hallo.apply[A]) 

... aber auch das:

class Bar[A](hallo: Hallo[A] = Hallo())  // ??? 
+2

Keine Antwort, aber drei Dinge zu beachten: Sie könnten den Typparameter etwas anderes als 'A' nennen, um Verwechslungen mit dem (anderen)' A' in der gefundenen: [A] scala.collection zu vermeiden. unveränderlich.Set [A] 'Nachricht; Die wichtige Tatsache sowohl bei 'Set' als auch bei' Hallo' ist, dass sie invariant sind (im Gegensatz zu 'List'); und deine letzte Zeile kompiliert setzt vermutlich nicht was du willst. –

+1

Während 'class Bar [A] (hallo: Hallo [A] = Hallo.apply)' wenn Sie es ändern, um 'Hallo.apply()' zu verwenden, funktioniert es gut. Du solltest die Parens auslassen können, also muss es hier wirklich durcheinander kommen. Es denkt, dass Sie die teilweise angewendete Funktion 'Hallo.Anwendung' übergeben, anstatt'Anwenden' ohne Argumente aufzurufen. (Die Fehlermeldung besagt, dass der Typ '[A]() Hallo [A]' gefunden wurde.) – DaoWen

Antwort

5

Sie den Typ direkt auf der empty Methode angeben können, anstatt den zusätzlichen Satz von Pars/Klammern und die Art Anmerkung hinzuzufügen:

class Bar[A](set: Set[Foo[A]] = Set.empty[Foo[A]]) 

Was, warum die Typinferenz fehlschlägt, finden diese Fragen :

Update:

Ich entschuldige mich, meine hastige Antwort war weg. Das Problem in den obigen Beiträgen steht nicht wirklich mit diesem Problem in Zusammenhang. @TravisBrown hat in seinem Kommentar oben einen sehr guten Punkt gemacht. Dies scheint auf den ersten zu arbeiten:

class Bar[A](set: Set[A] = Set.empty) 

Aber wenn Sie tatsächlich versuchen, den Konstruktor zu nennen es bei Verwendung vor Ort versagt:

new Bar[Int] 
// <console>:9: error: type mismatch; 
// found : scala.collection.immutable.Set[Nothing] 
// required: Set[Int] 
// Note: Nothing <: Int, but trait Set is invariant in type A. 
// You may wish to investigate a wildcard type such as `_ <: Int`. (SLS 3.2.10) 
// Error occurred in an application involving default arguments. 
//    new Bar[Int] 

Dies deutet darauf hin, dass der Compiler nicht die Standardkonfiguration erzwingen Parameter gilt für alle A, nur für einige A. Sie haben wahrscheinlich, dass die Wahl, so dass Sie etwas tun können:

scala> case class MyClass[T](set: Set[T] = Set(0)) 
defined class MyClass 

scala> MyClass() // defaults to MyClass[Int] 
res0: MyClass[Int] = MyClass(Set(0)) 

scala> MyClass(Set('x)) // but I can still use other types manually 
res1: MyClass[Symbol] = MyClass(Set('x)) 

jedoch jede Art von mit dem parametrisierten Typ Verschachtelung nicht bei der Deklaration Ort überprüfen geben im Konstruktor:

class Bar[A](set: Set[Option[A]] = Set.empty) 
// <console>:7: error: polymorphic expression cannot be instantiated to expected type; 
// found : [A]scala.collection.immutable.Set[A] 
// required: Set[Option[?]] 
//  class Bar[A](set: Set[Option[A]] = Set.empty) 

Der Folgerung nicht scheitern, wenn der Typ-Parameter in einer kovarianten Position ist:

class Bar[ A ](set: List[Foo[A]] = List.empty) // OK 

class Bar[ A ](set: Map[Int,Foo[A]] = Map.empty) // OK (unless you use it) 

class Bar[ A ](set: Map[Foo[A],Int] = Map.empty) // BAD 
// <console>:8: error: polymorphic expression cannot be instantiated to expected type; 
// found : [A, B]scala.collection.immutable.Map[A,B] 
// required: Map[Foo[?],Int] 
//   class Bar[ A ](set: Map[Foo[A],Int] = Map.empty) // BAD 
//              ^

Diese werden zu arbeiten, weil der Compiler Nothing als Co wählt Variantentyp standardmäßig.Das funktioniert gut für List, aber das zweite Beispiel funktioniert nicht, wenn Sie tatsächlich versuchen, es aufzurufen.

Die Ursache der meisten dieser Seltsamkeit ist wahrscheinlich die Art, wie Scala Standardargumente behandelt. Der Compiler fügt dem Companion-Objekt automatisch eine zusätzliche Methode hinzu, und überall, wo Sie ein Argument auslassen, fügt der Compiler automatisch einen Methodenaufruf zu der neuen Methode im Companion-Objekt hinzu, um stattdessen das fehlende Argument zu generieren. Es sieht so aus, als würde das Abstrahieren des Standardarguments in eine Methode einige Dinge in der Typinferenz brechen, die mit einer normalen Zuweisung funktionieren würden.

Ich denke, dass die meisten dieser Ergebnisse ziemlich verwirrend sind. Was ich davon wegnehme, ist, dass es wichtig ist, deine Standardparameter zu testen, um sicher zu gehen, dass sie die Typkorrektheit nicht brechen, wenn du sie verwendest!

+0

Ja, mir sind die Typparameter für 'leer' bekannt; Ich wollte nur zeigen, dass das Casting den Typ vollständig auflöst, anders als der erwartete Typ für das Standardargument. Das ergibt für mich keinen Sinn. Ich sehe das auch nicht in Bezug auf Fragen zu 'toSet', auf die Sie verlinken. –

+0

Sie haben recht, nachdem ich meine Antwort geschrieben habe, wurde mir klar, dass dies nicht der gleiche Fall war wie die anderen beiden Links, die ich gepostet habe. Lassen Sie mich ein bisschen mehr graben ... Da es jedoch funktioniert, wenn Sie in Ihrem Beispiel eine 'List' anstelle eines' Set' verwenden, denke ich, dass es verwandt ist. – DaoWen

+0

@ 0__ - Ich habe einige wesentliche Änderungen an meiner Antwort vorgenommen, daher sollten Sie sie vielleicht noch einmal durchlesen. Ich bin mir immer noch nicht sicher, ob ich deine erste Frage beantwortet habe - ich habe vielleicht nur weitere Fragen hinzugefügt. – DaoWen

Verwandte Themen