Why does this Iterable create a set after matching?

In the code example below, why does Iterable [String] test1create a set after matching?

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

I was puzzled by this because it is completely counterintuitive when reading code. Even if it foo.keyssimply returns Iterable, it creates a Set when called map, as the reflection code shows:

println(test1.map(foo).getClass.getName) // immutable.Set.Set1
println(test2.map(foo).getClass.getName) // Iterator$$anon$11

How does the standard library determine what it should create immutable.Sethere, although the intended type of collection is simple Iterable[String]?

+4
source share
3 answers

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], a 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, , :

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]

Q & A breakOut.

+2

foo.keys a Set ( , ), Set Set. .

, keys Set a Set, Iterable[A]:

scala> Map(1 -> 2).keys
res0: Iterable[Int] = Set(1)
+5

. : CanBuildFrom, . , .

, foo.keys Set. : Set ( Java HashMap/HashSet ). iterable, implicits , Set ( , CanBuildFrom , , ).

Scala Java "- - ". "de-jure" , "-" . , , Map.keys type Iterable, - Set ( Map.keySet, Set de-jure).

, 1 println , foo , Set(1,1) Set(1).

0

Source: https://habr.com/ru/post/1651892/


All Articles