挖掘了Kolmar的评论,尽管一个隐含的参数正在决定如何构建结果集合,但在这种情况下,只需查询源集合以供构建器使用。
Iterable.map
:
def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[Iterable[A], B, That]): That
隐范围包括与类型指定参数时,包括Iterable
和Int
类型。
Iterable
定义了在源集合上调用genericBuilder
的“generic”CanBuildFrom
。这就是结果类型与源相关联的方式。
相反,结果集合通过采取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[_], Int, List[Int]] {
| def apply() = new ListBuffer[Int]
| def apply(from: Iterable[_]) = apply()
| }
as$u0020list: scala.collection.generic.CanBuildFrom[Iterable[_],Int,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, Int, scala.collection.immutable.IndexedSeq[Int]](scala.Predef.fallbackStringCanBuildFrom[Int])) // : scala.collection.immutable.IndexedSeq[Int]
如图所示,它实际上是拾取CanBuildFrom
int结束了对诸如操作:
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], Int, List[Int]](scala.collection.immutable.List.canBuildFrom[Int]))): scala.`package`.List[scala.Int]) // : List[Int]
的canonical Q&A on breakOut。
另外值得一提的是,覆盖将类型绑定到源代码的常用机制是使用'scala.collection.breakOut'。因此'foo.keys.map(foo)(collection.breakOut)'将产生Vector(1,1):scala.collection.immutable.IndexedSeq [Int]'。这也允许从结果中进行类型推断,所以'val l:List [Int] = foo.keys.map(foo)(collection.breakOut)'将产生运行时的'List(1,1)'。 – Kolmar
还有一个社区答案选项,但我不知道击键的关键。现在必须赶快离开。 –