Преобразование из Seq в Set и обратно в Seq - PullRequest
10 голосов
/ 25 марта 2011

Интуитивно понятно, что должно работать следующее:

case class I(i: Int)
val s = Seq(I(1),I(2),I(3))
s.sortBy(_.i)             // works
s.toSeq.sortBy(_.i)       // works
s.toSet.toSeq.sortBy(_.i) // doesn´t work

Почему оно не работает так, как ожидалось?

Ответы [ 2 ]

15 голосов
/ 25 марта 2011

Это сложное влияние смешивания ковариантных и инвариантных коллекций.Набор инвариантен: Set[A].Но Seq является ковариантным: Seq[+A].Теперь представьте, что вы хотите иметь метод toSet в вашем Seq.Вы можете попробовать toSet: Set[A].Но это не сработает, потому что если A является подклассом B, то Seq[A] следует рассматривать как подкласс Seq[B].Однако Seq[A] настаивает на возвращении Set[A], который не подкласс Seq[B].Таким образом, наша типизация нарушена.

Если, с другой стороны, мы указываем toSeq[B >: A]: Set[B], тогда все в порядке: если мы обещаем, что можем вернуть любой суперкласс, тогда Seq[A] может вернуть Set[B], а такжеSet[C], где C - суперкласс B.Seq[B] пообещал вернуть Set[B] или еще немного Set[C], так что мы в курсе: метод на Seq[A] может сделать все, что может сделать метод на Seq[B].

НоТеперь посмотрим, с чем столкнулся бедный типер:

s.toSet[B >: I]
 .toSeq/* Type B >: I*/
 .sortBy[C](/* some f:B => C */)(/* implicit ordering on C */)

Там есть способ решить эту проблему, а именно - решить, что B равно I, и наберите функциюи C соответственно.Но это становится довольно сложным поиском, и это больше, чем компилятор может обработать прямо сейчас.Поэтому он просит вас помочь с типом ввода для функции, чтобы он знал B в этой точке (а затем может распространить его обратно на toSet).

Но вы можете, если хотитепомогите ему на нескольких уровнях:

s.toSet[I].toSeq.sortBy(_.i)
s.toSet.toSeq.sortBy[Int](_.i)

или вы можете помочь ему, продемонстрировав ему, что не нужно учитывать более поздние типы при выборе лучшего соответствия с более ранними типами:

{ val temp = s.toSet; temp }.toSeq.sortBy(_.i)
s.toSet match { case x => x.toSeq.sortBy(_.i) }
0 голосов
/ 25 марта 2011

Похоже, что-то, что связано с выводом типа, я не очень хорошо знаю.

Но оба из следующих приемов делают:

s.toSet.toSeq.asInstanceOf[Seq[I]].sortBy(_.i)
s.toSet.toSeq.sortWith(_.i < _.i)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...