Выполняя рефакторинг в приложении scala, я столкнулся с ситуацией, когда при переходе от List к Set возник вопрос, которого у меня раньше не было. У меня есть некоторое представление о дисперсии, но я хотел бы понять, что именно она означает для компилятора.
У меня было что-то подобное, которое компилируется и отлично работает:
case class MyClassList(s: List[Any])
val myList = List(("this", false)) // List[(String, Boolean)]
val listWorks = MyClassList(myList)
Затем я изменил свой список, чтобы установить:
case class MyClassSet(s: Set[Any])
val mySet = Set(("this", false)) // Set[(String, Boolean)]
val setFails = MyClassSet(mySet)
На этом этапе создание объекта типа MyClassSet больше не подходит, когда я передаю Set в качестве аргумента, даже если он принимает Set of Any. Теперь это немного сбивает с толку, когда работает следующее (обратите внимание, что набор «такой же», как и предыдущий mySet):
val setWorks1 = MyClassSet(Set(("this", false)))
Я считаю, что простое объяснение состоит в том, что компилятор выводит mySet val как Set [(String, Boolean)], но когда я создаю его непосредственно в списке аргументов setWorks1, поскольку он принимает Set [Any], компилятор выводя его как Set [Any]. Это делает первый пример неудачным, а второй - успешным. Эти также работают, что указывает на правильность предыдущего:
val setWorks2 = MyClassSet(mySet.toSet[Any])
val mySetOfAny: Set[Any] = Set(("this", false), ("that", true), ("other", false))
val setWorks3 = MyClassSet(mySetOfAny)
Фактическая ошибка, показанная компилятором:
Error:(15, 55) type mismatch;
found : Set[(String, Boolean)]
required: Set[Any]
Note: (String, Boolean) <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: (...)
Списки и наборы определены следующим образом:
type List[+A] = scala.collection.immutable.List[A]
type Set[A] = immutable.Set[A]
- Является ли эта разница в вариации типов, которая позволяет мне передавать список «более ограниченного типа, чем любой» в качестве аргумента, но не a в случае Set?
- Разве эта разница предотвращает только приведение типов или преобразование между ними?
- Это в основном «ограничение» компилятора или ожидаемое свойство инвариантного типа?
- Есть ли какие-то другие различия между инвариантными типами «на практике» или они сводятся к приведению типов, как это?