2016-10-13 3 views
0

Выполняя рефакторинг в приложении scala, я столкнулся с ситуацией, когда переход от List to Set вызвал вопрос, который у меня не был раньше. У меня есть некоторое представление о дисперсии, но я хотел бы понять, что это значит для компилятора.Scala 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 как аргумент, даже когда он принимает Набор Людей. Теперь это стало немного запутанным, когда следующие работы (обратите внимание, что множество «такой же», как и предыдущий Инд.Сброс):

val setWorks1 = MyClassSet(Set(("this", false))) 

Я считаю, что простое объяснение состоит в том, что компилятор выводя Инд.Сброс Вэл как Установите [(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] 
  • Является ли это разницей в дисперсии типа, которая позволяет мне передавать список «более ограниченного типа, чем любой» в качестве аргумента, но не в случае от Set?
  • Разве это различие предотвращает литье или преобразование между типами?
  • Является ли это главным образом компилятором «ограничение» или ожидаемое свойство инвариантного типа?
  • Существуют ли какие-либо другие различия между инвариантными типами «на практике» или они сводятся к кастингу, например?

ответ

0

1) Это объясняется здесь: Why is Scala's immutable Set not covariant in its type?

В принципе, набор [T] также Function1[T, Boolean]. Подпись Function1 составляет [-In, +Out], поэтому T не может быть как +T, так и -T в то же время, что и scala не допускает бивариации (это значительно ослабит систему типов).

2) Вы можете легко отливать его, используя .toSet[Any] (который является оберткой над asInstanceOf). Существует также путь к skip variance check.

3, 4) Ожидается свойство родовых (полиморфных) типов. Они могут быть инвариантными/ковариантными/контравариантными (а не только) и формально описываются простыми правилами. Вы можете прочитать объяснение здесь: https://stackoverflow.com/a/27627891/1809978

+0

Принимая ваш ответ, так как после прочтения всех других ответов в связанных ответах я получил свой мозг вокруг него.Фактическое различие в 1) хорошо объясняет, почему Set является инвариантным (также потому, что он реализован с использованием карт с инвариантным ключом. – negative

Смежные вопросы