EDYCJA : Ponownie napisano to pytanie na podstawie oryginalnej odpowiedzi
scala.collection.immutable.Set
Klasa nie jest kowariantna w jego parametr typu. Dlaczego to?
import scala.collection.immutable._
def foo(s: Set[CharSequence]): Unit = {
println(s)
}
def bar(): Unit = {
val s: Set[String] = Set("Hello", "World");
foo(s); //DOES NOT COMPILE, regardless of whether type is declared
//explicitly in the val s declaration
}
scala
set
covariance
scala-collections
oxbow_lakes
źródło
źródło
foo(s.toSet[CharSequence])
kompiluje się dobrze.toSet
Sposób O (1) - nie tylko otaczaasInstanceOf
.foo(Set("Hello", "World"))
kompiluje się również w wersji 2.10, ponieważ Scala wydaje się być w stanie wywnioskować właściwy typ Set. Nie działa jednak z niejawnymi konwersjami ( stackoverflow.com/questions/23274033/… ).Odpowiedzi:
Set
jest niezmienna w swoim parametrze typu ze względu na koncepcję zbiorów jako funkcji. Poniższe podpisy powinny nieco wyjaśnić:trait Set[A] extends (A=>Boolean) { def apply(e: A): Boolean }
Gdyby
Set
były kowariantne wA
,apply
metoda nie mogłaby przyjąć parametru typuA
ze względu na kontrawariancję funkcji.Set
może potencjalnie być sprzeczne w programieA
, ale to również powoduje problemy, gdy chcesz robić takie rzeczy:def elements: Iterable[A]
Krótko mówiąc, najlepszym rozwiązaniem jest zachowanie niezmienności elementów, nawet w przypadku niezmiennej struktury danych. Zauważysz, że
immutable.Map
jest to również niezmienne w jednym z parametrów typu.źródło
List(1,2,3).contains _
to(Any) => Boolean
, a typSet(1,2,3).contains _
tores1: (Int) => Boolean
.na http://www.scala-lang.org/node/9764 Martin Odersky pisze:
Wygląda więc na to, że wszystkie nasze wysiłki zmierzające do skonstruowania pryncypialnego powodu były błędne :-)
źródło
Seq
są kowariantne ... czy czegoś mi brakuje?Array[Any]
wewnętrznie.EDYCJA : dla każdego, kto zastanawia się, dlaczego ta odpowiedź wydaje się nieco nie na temat, to dlatego, że ja (pytający) zmodyfikowałem pytanie.
Wnioskowanie o typie Scali jest wystarczająco dobre, aby dowiedzieć się, że w niektórych sytuacjach chcesz CharSequences, a nie Strings. W szczególności działa dla mnie w 2.7.3:
import scala.collections.immutable._ def findCharSequences(): Set[CharSequence] = Set("Hello", "World")
Jeśli chodzi o bezpośrednie tworzenie niezmiennych.HashSets: nie. W ramach optymalizacji implementacji immutable.HashSets zawierające mniej niż 5 elementów nie są w rzeczywistości wystąpieniami immutable.HashSet. Są to EmptySet, Set1, Set2, Set3 lub Set4. Klasy te stanowią podklasę immutable.Set, ale nie immutable.HashSet.
źródło