本文介绍了toSet 和类型推断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can somebody explain why the following does not work. Somehow looses the compile some information for the type inference when i do toSet, but i don't understand why.

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))

推荐答案

假设我有以下内容:

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 是协变的.这意味着如果我有一个 List[Dog] 我也有一个 List[Pet],但是一个 Set[Dog]不是Set[Pet].为方便起见,Scala 允许您在从 List(或其他集合类型)到 Set 的转换期间通过在 上提供显式类型参数进行向上转换设置.当你写 val a = ids.toSet;a.map(...),这个类型参数是推断出来的,你没问题.另一方面,当您编写 ids.toSet.map(...) 时,它不会被推断出来,因此您很不走运.

Set isn't covariant in its type parameter, but List is. This means if I have a List[Dog] I also have a List[Pet], but a Set[Dog] is not a Set[Pet]. For the sake of convenience, Scala allows you to upcast during a conversion from a List (or other collection types) to a Set by providing an explicit type parameter on toSet. When you write val a = ids.toSet; a.map(...), this type parameter is inferred and you're fine. When you write ids.toSet.map(...), on the other hand, it's not inferred, and you're out of luck.

这允许以下工作:

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)
                                               ^

这值得混淆吗?我不知道.但这有点道理,这是 Collections API 设计者为 toSet 做出的决定,所以我们坚持了下去.

Is this worth the confusion? I don't know. But it kind of makes sense, and it's the decision the Collections API designers made for toSet, so we're stuck with it.

这篇关于toSet 和类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-11 00:39