为什么这个Iterable在映射后产生一个Set?

Chr*_*ris 4 collections dictionary iterator iterable scala

在下面的示例代码中,为什么Iterable [String] test1在映射后生成一个Set?

val foo = Map("a" -> 1, "b" -> 1)
val test1: Iterable[String] = foo.keys
val test2: Iterator[String] = foo.keys.toIterator

println(test1.map(foo).size) // 1
println(test2.map(foo).size) // 2
Run Code Online (Sandbox Code Playgroud)

我对此感到困惑,因为在阅读代码时它完全违反直觉.即使foo.keys只返回一个Iterable,它也会在调用时创建一个Set map,如反射代码所示:

println(test1.map(foo).getClass.getName) // immutable.Set.Set1
println(test2.map(foo).getClass.getName) // Iterator$$anon$11
Run Code Online (Sandbox Code Playgroud)

标准库如何确定它应该在immutable.Set这里创建一个,即使该集合的推断类型只是Iterable[String]

Kim*_*bel 5

foo.keys返回一个Set(尽管它的返回类型更通用)并且在一个上调用map Set会产生另一个Set.推断或编译时间类型并不总是最精确的.

您可以看到a上的keys方法Set返回a,Set即使返回类型Iterable[A]:

scala> Map(1 -> 2).keys
res0: Iterable[Int] = Set(1)
Run Code Online (Sandbox Code Playgroud)

  • @克里斯`Set`是Iterable`的`子类,因此`Map.keys`只是调用`keySet`并返回`Set`作为`Iterable`:https://github.com/scala/scala/blob/ v2.11.8/src目录/库/斯卡拉/收集/ MapLike.scala#L192 (2认同)