挖掘了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
還有一個社區答案選項,但我不知道擊鍵的關鍵。現在必須趕快離開。 –