Scala集合中的森林砍伐

Pau*_*ner 5 collections scala implicits

从Scala集合的设计中我理解如下:

scala> BitSet(1,2,3) map (_ + "a")
res7: scala.collection.immutable.Set[String] = Set(1a, 2a, 3a)
Run Code Online (Sandbox Code Playgroud)

不构建中间数据结构:新的Set是在使用Builder迭代BitSet时构建的.事实上,在这种情况下很明显,因为字符串的位组没有意义.

列表中的地图怎么样?我很确定以下内容构建了一个中间列表:

scala> List(1,2,3) map (_ -> "foo") toMap
res8: scala.collection.immutable.Map[Int,java.lang.String] =
    Map(1 -> foo, 2 -> foo, 3 -> foo)
Run Code Online (Sandbox Code Playgroud)

即清单List((1,foo), (2,foo), (3,foo)).如果没有,那怎么样?现在,以下怎么样?

scala> Map.empty ++ (List(1,2,3) map (_ -> "foo"))
res10: scala.collection.immutable.Map[Int,java.lang.String] =
    Map(1 -> foo, 2 -> foo, 3 -> foo)
Run Code Online (Sandbox Code Playgroud)

这一次,从我似乎从以下类型的理解++:

def ++ [B >: (A, B), That]
       (that: TraversableOnce[B])
       (implicit bf: CanBuildFrom[Map[A, B], B, That]): That
Run Code Online (Sandbox Code Playgroud)

认为可能是地图是动态构建的,并且没有构建中间列表.

是这样的吗?如果是,这是确保森林砍伐的规范方式还是更直接的语法?

mis*_*tor 14

您可以使用breakOut以确保不创建任何中间集合.例如:

// creates intermediate list.
scala> List((3, 4), (9, 11)).map(_.swap).toMap 
res542: scala.collection.immutable.Map[Int,Int] = Map(4 -> 3, 11 -> 9)

scala> import collection.breakOut
import collection.breakOut

// doesn't create an intermediate list.
scala> List((3, 4), (9, 11)).map(_.swap)(breakOut) : Map[Int, Int]
res543: Map[Int,Int] = Map(4 -> 3, 11 -> 9)
Run Code Online (Sandbox Code Playgroud)

你可以在这里阅读更多相关信息.

更新:

如果您阅读了定义breakOut,您会注意到它基本上是一种创建CanBuildFrom预期类型对象并将其显式传递给方法的方法.breakOut只是节省您输入以下样板文件.

// Observe the error message. This will tell you the type of argument expected.
scala> List((3, 4), (9, 11)).map(_.swap)('dummy)
<console>:16: error: type mismatch;
 found   : Symbol
 required: scala.collection.generic.CanBuildFrom[List[(Int, Int)],(Int, Int),?]
              List((3, 4), (9, 11)).map(_.swap)('dummy)
                                                ^

// Let's try passing the implicit with required type.
// (implicitly[T] simply picks up an implicit object of type T from scope.)
scala> List((3, 4), (9, 11)).map(_.swap)(implicitly[CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]]])
// Oops! It seems the implicit with required type doesn't exist.
<console>:16: error: Cannot construct a collection of type Map[Int,Int] with elements of type (Int, Int) based on a coll
ection of type List[(Int, Int)].
              List((3, 4), (9, 11)).map(_.swap)(implicitly[CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]]])

// Let's create an object of the required type ...
scala> object Bob extends CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]] {
     |   def apply(from: List[(Int, Int)]) = foo.apply
     |   def apply() = foo.apply
     |   private def foo = implicitly[CanBuildFrom[Nothing, (Int, Int), Map[Int, Int]]]
     | }
defined module Bob

// ... and pass it explicitly.
scala> List((3, 4), (9, 11)).map(_.swap)(Bob)
res12: Map[Int,Int] = Map(4 -> 3, 11 -> 9)

// Or let's just have breakOut do all the hard work for us.
scala> List((3, 4), (9, 11)).map(_.swap)(breakOut) : Map[Int, Int]
res13: Map[Int,Int] = Map(4 -> 3, 11 -> 9)
Run Code Online (Sandbox Code Playgroud)

  • 哇,确实需要542次尝试才能做到这一点;-) (3认同)
  • @DuncanMcGregor:过去5天我没有关闭REPL.我在日常生活中大量使用它.:-) (3认同)
  • @DuncanMcGregor:我的Windows终于崩溃了.:-D (3认同)