Scala Set, что происходит с инвариантными типами?
Выполняя рефакторинг в приложении 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], компилятор выводя его как набор [любой]. Это приводит к тому, что первый пример терпит неудачу, а второй проходит. Эти также работают, что указывает на правильность предыдущего:
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]
- Является ли это различие в типовой дисперсии, которое позволяет мне передавать список "более ограниченного типа, чем любой" в качестве аргумента, но не в случае Set?
- Разве эта разница только мешает приведению или преобразованию между типами?
- В основном это "ограничение" компилятора или ожидаемое свойство инвариантного типа?
- Существуют ли какие-либо другие различия между инвариантными типами "на практике" или они сводятся к приведению типа этого?
1 ответ
1) Это объясняется здесь: почему неизменяемое множество Скалы не ковариантно по своему типу?
По сути, Set[T] также Function1[T, Boolean]
, Подпись Function1
является [-In, +Out]
, так T
не может быть и то и другое +T
а также -T
в то же время скала не допускает бивариантности (это значительно ослабит систему типов).
2) Вы можете легко разыграть его, используя .toSet[Any]
(который является оберткой над asInstanceOf
). Существует также способ пропустить проверку дисперсии.
3, 4) Ожидаемое свойство универсальных (полиморфных) типов. Они могут быть инвариантными / ковариантными / контравариантными (не только), и это формально описывается простыми правилами. Вы можете прочитать объяснение здесь: /questions/29264769/znaki-v-rodovoj-deklaratsii-v-scala/29264774#29264774