Ответ 1
Предположим, у меня есть следующее:
trait Pet {
def name: String
}
case class Dog(name: String) extends Pet
val someDogs: List[Dog] = List(Dog("Fido"), Dog("Rover"), Dog("Sam"))
Set
не является ковариантным в своем параметре типа, но List
is. Это означает, что если у меня есть List[Dog]
, у меня также есть List[Pet]
, но a Set[Dog]
не является Set[Pet]
. Для удобства Scala позволяет вам ускорить преобразование из List
(или других типов коллекций) в Set
путем предоставления явного параметра типа на toSet
. Когда вы пишете val a = ids.toSet; a.map(...)
, этот параметр типа выводится, и вы в порядке. Когда вы пишете ids.toSet.map(...)
, с другой стороны, это не выводится, и вам не повезло.
Это позволяет работать следующим образом:
scala> val twoPetSet: Set[Pet] = someDogs.toSet.take(2)
twoPetSet: Set[Pet] = Set(Dog(Fido), Dog(Rover))
Пока это не так:
scala> val allDogSet: Set[Dog] = someDogs.toSet
allDogSet: Set[Dog] = Set(Dog(Fido), Dog(Rover), Dog(Sam))
scala> val twoPetSet: Set[Pet] = allDogSet.take(2)
<console>:14: error: type mismatch;
found : scala.collection.immutable.Set[Dog]
required: Set[Pet]
Note: Dog <: Pet, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Pet`. (SLS 3.2.10)
val twoPetSet: Set[Pet] = allDogSet.take(2)
^
Неужели это стоит путаницы? Я не знаю. Но это имеет смысл, и это решение дизайнеров API коллекций сделано для toSet
, поэтому мы застряли с ним.