Staram się pojąć kowariancję i kontrawariancję w Scali. Mam taki zestaw klas Wiadomość 1 i Wiadomość 2 są podtypami komunikatu
sealed trait Parser[T <: Message]{
//... blah blah
}
class Parser1 extends Parser[Message1]{
}
class Parser2 extends Parser[Message2]{
}
Teraz mam inny moduł (fabryka), który przechowuje mapowania na niezmiennej mapie
var myMap = Map[String,Parser[Message]()
myMap += Map("Message1" -> new Parser1)
myMap += Map("Message2"-> new Parser2)
Teraz to się nie kompiluje. czego mi brakuje?
To błąd kompilacji, który otrzymuję
[error] found : scala.collection.immutable.Map[java.lang.String,s.p.h.m.Parser1]
[error] required: (String, s.p.h.m.Parser[c.s.m.Message])
[error] myMap += Map("Message1" -> new Parser1)
Odpowiedzi:
2 dla odpowiedzi № 1Widziałeś już, że potrzebujesz ++=
aby dodać wpisy innej mapy do mapy, podczas gdy +
przyjmuje pojedynczy wpis (krotkę klucza i wartości). Jeśli chcesz zachować var
, musisz się tego upewnić Parser
jest kowariantem w T
po to aby Parser[Message1]
jest uważany za podtyp Parser[Message]
(ponieważ wynik +
będzie najbliższym nadtypem istniejących wpisów i nowego wpisu, który w takim przypadku pozostanie Map[String,Parser[Message]]
i dlatego można go ponownie zapisać w myMap
):
trait Message; class Message1 extends Message; class Message2 extends Message
sealed trait Parser[+T <: Message] // !
class Parser1 extends Parser[Message1]
class Parser2 extends Parser[Message2]
var myMap = Map.empty[String,Parser[Message]]
myMap += "Message1" -> new Parser1
myMap += "Message2"-> new Parser2
myMap ++= Map( "Message1b"-> new Parser1, "Message2b"-> new Parser2 )
2 dla odpowiedzi nr 2
Jaki błąd otrzymujesz? Nie wygląda to tak, jakbyś miał tutaj jakieś błędy typu z powodu twojego Parser
hierarchia klas.
Wygląda jednak na to, że próbujesz zmutować niezmienną mapę i tak dalej byłoby spowodować błąd. Powinieneś także dodać para map do mapy zamiast nowa mapa. Spróbuj tego:
val myMap = Map[String,Parser]()
val myMap1 = myMap + ("Message1" -> new Parser1)
val myMap2 = myMap1 + ("Message2" -> new Parser2)
Jeśli naprawdę chcesz skorzystać +=
zamiast tworzyć nowy val
dla każdej aktualizacji możesz użyć scala.collection.mutable.Map
zamiast domyślnego (niezmiennego) typu mapy.