Это сложное влияние смешивания ковариантных и инвариантных коллекций.Набор инвариантен: 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) }