2012-08-08 8 views
8

Ich möchte eine kovariante Klasse erstellen, die veränderbar ist, also muss ich einen niedrigeren Typ hinzufügen, der an die Setter-Methode gebunden ist. Aber ich möchte auch die Setter-Methode, um ein Feld zu setzen, also denke ich, das Feld muss den gleichen Typ gebunden haben?Unterer Typ gebunden an Scala-Feld in veränderbarer, kovarianter Klasse?

class Thing[+F](initialValue: F) { 

    private[this] var secondValue: Option[G >: F] = None 

    def setSecondValue[G >: F](v: G) = { 
     this.secondValue = Some(v) 
    } 
} 

Die Methode kompiliert fein. Aber das Feld secondValue kompiliert überhaupt nicht mit der Fehlermeldung:

Multiple markers at this line 
     - ']' expected but '>:' found. 
     - not found: type G 

Was muss ich tun?

Antwort

8

Sie benötigen das forSome Konstrukt, das G als existenzielle Art führt:

class Thing[+F](initialValue: F) { 
    private[this] var secondValue: Option[G] forSome { type G >: F} = None 

    def setSecondValue[G >: F](v: G) = { 
    this.secondValue = Some(v) 
    } 
} 

In Ihrem ursprünglichen Code für secondValue hat G aus der Luft gezogen worden, das heißt, es ist nicht richtig eingeführt. Im Fall von setSecondValue bindet der Benutzer (oder der Compiler) G an Call-Site, aber für ein Feld, das keine Option ist (insbesondere, da Ihre privat ist). Lesen Sie mehr über forSome und existentielle Typen in Scala here, here oder here.

+0

Perfect - das tut, was ich will. Ich habe versucht mit forSome auf der Methode und das funktioniert auch: def setSecondAroma (secondAroma: G forSome {Typ G>: F}) = ... –

+0

@JohnSmith Ich weiß nicht, wenn forSome G in setSecondValue hat eine (dis) Vorteile im Vergleich zu nur mit einem regulären Argument Typ G. Sollten Sie wissen/finden Sie heraus, bitte hier posten. –

+2

Beachten Sie, dass der Typ 'G' in dem Feld hier nichts mit dem Typ' G' zu tun hat. –

11

@mhs Antwort ist richtig.

Sie können auch Wildcard-Syntax verwenden (wie in Java), die genau die gleiche Bedeutung hat:

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

class Thing[+F](initialValue: F) { 
    private[this] var secondValue: Option[_ >: F] = None 

    def setSecondValue[G >: F](v: G) = { 
    this.secondValue = Some(v) 
    } 

    def printSecondValue() = println(secondValue) 
} 

// Exiting paste mode, now interpreting. 

defined class Thing 

scala> val t = new Thing(Vector("first")) 
t: Thing[scala.collection.immutable.Vector[java.lang.String]] = [email protected] 

scala> t.printSecondValue() 
None 

scala> t.setSecondValue(Seq("second")) 

scala> t.printSecondValue() 
Some(List(second)) 
+0

hmm, ich glaube, ich akzeptierte zu schnell. das scheint eine elegantere Lösung zu sein. –

Verwandte Themen