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

Другие вопросы по тегам