设置和输入推断

reg*_*exp 10 scala

有人可以解释为什么以下不起作用.当我这样做时toSet,不知何故失去了编译类型推断的一些信息,但我不明白为什么.

scala> case class Foo(id: Int, name: String)
defined class Foo

scala> val ids = List(1,2,3)
ids: List[Int] = List(1, 2, 3)

scala> ids.toSet.map(Foo(_, "bar"))
<console>:11: error: missing parameter type for expanded function ((x$1) => Foo(x$1, "bar"))
              ids.toSet.map(Foo(_, "bar"))
                                ^

scala> ids.map(Foo(_, "bar")).toSet
res1: scala.collection.immutable.Set[Foo] = Set(Foo(1,bar), Foo(2,bar), Foo(3,bar))
Run Code Online (Sandbox Code Playgroud)

Tra*_*own 6

假设我有以下内容:

trait Pet {
  def name: String
}

case class Dog(name: String) extends Pet

val someDogs: List[Dog] = List(Dog("Fido"), Dog("Rover"), Dog("Sam"))
Run Code Online (Sandbox Code Playgroud)

Set它的类型参数不是协变的,但是List.这意味着,如果我有List[Dog]我也有List[Pet],但Set[Dog]就是没有一个Set[Pet].为方便起见,Scala允许您在从List(或其他集合类型)到a 的转换期间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))
Run Code Online (Sandbox Code Playgroud)

虽然这不是:

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)
                                               ^
Run Code Online (Sandbox Code Playgroud)

这值得混淆吗?我不知道.但这有点意义,而且这是Collections API设计师所做出的决定toSet,因此我们坚持使用它.