scala – 为什么这个Iterable在映射后产生一个Set?
在下面的示例代码中,为什么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 我对此感到困惑,因为在阅读代码时它完全违反直觉.即使foo.keys只返回一个Iterable,它在调用map时会创建一个Set,因为反射代码显示: println(test1.map(foo).getClass.getName) // immutable.Set.Set1 println(test2.map(foo).getClass.getName) // Iterator$$anon$11 标准库如何确定它应该在这里创建一个immutable.Set,即使该集合的推断类型只是Iterable [String]? 解决方法
挖掘Kolmar的评论,虽然隐含的参数决定了如何构建结果集合,但在这种情况下,只需查询源集合以供构建器使用.
Iterable.map: def map[B,That](f: (A) ? B)(implicit bf: CanBuildFrom[Iterable[A],B,That]): That 隐式范围包括与类型args相关的类型,包括Iterable和Int. Iterable定义了一个“泛型”CanBuildFrom,它在源集合上调用genericBuilder.这就是结果类型与源相关联的方式. 相反,结果集合通过采用CanBuildFrom [From = Nothing,_,_]与源分离.这就是cc.to [Set]的表达方式,其中构建Set而不考虑源集合cc.对于诸如map之类的操作,方法collection.breakOut提供了这样的CanBuildFrom,其中可以有效地推断出结果类型. 您可以为所需行为注入任意CanBuildFrom: $scala Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM,Java 1.8.0_92). Type in expressions for evaluation. Or try :help. scala> val m = Map("a" -> 1,"b" -> 1) m: scala.collection.immutable.Map[String,Int] = Map(a -> 1,b -> 1) scala> val k = m.keys k: Iterable[String] = Set(a,b) scala> import collection.{generic,mutable},generic.{CanBuildFrom => CBF},mutable.ListBuffer import collection.{generic,mutable} import generic.{CanBuildFrom=>CBF} import mutable.ListBuffer scala> implicit def `as list`: CBF[Iterable[_],Int,List[Int]] = | new CBF[Iterable[_],List[Int]] { | def apply() = new ListBuffer[Int] | def apply(from: Iterable[_]) = apply() | } as$u0020list: scala.collection.generic.CanBuildFrom[Iterable[_],List[Int]] scala> k.map(m) res0: List[Int] = List(1,1) 值得补充的是,完成可以显示2.11.8中的类型: scala> k.map(m) //print<tab> $line4.$read.$iw.$iw.k.map[Int,Iterable[Int]]($line3.$read.$iw.$iw.m)(scala.collection.Iterable.canBuildFrom[Int]) // : Iterable[Int] 使用breakOut: scala> k.map(m)(collection.breakOut) res1: scala.collection.immutable.IndexedSeq[Int] = Vector(1,1) scala> k.map(m)(collection.breakOut) //print $line4.$read.$iw.$iw.k.map[Int,scala.collection.immutable.IndexedSeq[Int]]($line3.$read.$iw.$iw.m)(scala.collection.`package`.breakOut[Any,scala.collection.immutable.IndexedSeq[Int]](scala.Predef.fallbackStringCanBuildFrom[Int])) // : scala.collection.immutable.IndexedSeq[Int] 如图所示,它实际上会为以下操作选择CanBuildFrom: scala> "abc".map(_ + 1) res2: scala.collection.immutable.IndexedSeq[Int] = Vector(98,99,100) scala> "abc".map(_ + 1) //print scala.Predef.augmentString("abc").map[Int,scala.collection.immutable.IndexedSeq[Int]](((x$1: Char) => x$1.+(1)))(scala.Predef.fallbackStringCanBuildFrom[Int]) // : scala.collection.immutable.IndexedSeq[Int] 相比: scala> k.map(m)(collection.breakOut) : List[Int] //print (($line6.$read.$iw.$iw.k.map[Int,List[Int]]($line5.$read.$iw.$iw.m)(scala.collection.`package`.breakOut[Iterable[String],List[Int]](scala.collection.immutable.List.canBuildFrom[Int]))): scala.`package`.List[scala.Int]) // : List[Int] canonical Q&A on breakOut. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |