2012-08-08 16 views
8

Chcę utworzyć klasę kowariantyczną, która jest zmienna, więc muszę dodać niższy typ związany z metodą ustawiającą. Ale chcę również, aby metoda ustawiająca ustawiła pole, więc domyślam się, że pole musi być powiązane z tym samym typem?Dolny typ związany w polu Scala w zmiennym, zmiennym klasie?

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

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

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

Metoda kompiluje dobrze. Ale pole o nazwie secondValue nie skompilować w ogóle, z komunikatem o błędzie:

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

Co muszę zrobić?

Odpowiedz

8

Musisz forSome konstrukt, który wprowadza G jak rodzaj egzystencjalnej:

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) 
    } 
} 

w oryginalnej kodu dla secondValue, G została wyciągnięta z powietrza, to znaczy, że nie zostało wprowadzone poprawnie. W przypadku setSecondValue użytkownik (lub kompilator) wiąże się z G na stronie wywołania, ale dla pola, które nie jest opcją (szczególnie, ponieważ twoja jest prywatna). Przeczytaj więcej na temat forSome i typów egzystencjalnych w Scala here, here lub here.

+0

doskonały - robi to, co chcę. Próbowałem używać forSome w metodzie i to też działa: def setSecondAroma (secondAroma: G forSome {type G>: F}) = ... –

+0

@JohnSmith Nie wiem, czy użycie forSome G w setSecondValue ma jakieś (dis) zalety w porównaniu do zwykłego argumentu typu G. Jeśli znasz/dowiadujesz się, opublikuj go tutaj. –

+2

Należy zauważyć, że typ 'G' w polu nie ma nic wspólnego z typem' G' w metodzie tutaj. –

11

odpowiedź @ hm jest właściwa.

Można również użyć symboli wieloznacznych składni (jak w java), który ma dokładnie takie samo znaczenie:

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, myślę, że przyjąłem zbyt szybko. to wydaje się bardziej eleganckie rozwiązanie. –

Powiązane problemy