Scala 2.8 breakOut

后端 未结 4 1036
无人及你
无人及你 2020-11-22 03:43

In Scala 2.8, there is an object in scala.collection.package.scala:

def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing         


        
4条回答
  •  余生分开走
    2020-11-22 03:46

    I'd like to build upon Daniel's answer. It was very thorough, but as noted in the comments, it doesn't explain what breakout does.

    Taken from Re: Support for explicit Builders (2009-10-23), here is what I believe breakout does:

    It gives the compiler a suggestion as to which Builder to choose implicitly (essentially it allows the compiler to choose which factory it thinks fits the situation best.)

    For example, see the following:

    scala> import scala.collection.generic._
    import scala.collection.generic._
    
    scala> import scala.collection._
    import scala.collection._
    
    scala> import scala.collection.mutable._
    import scala.collection.mutable._
    
    scala>
    
    scala> def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) =
         |    new CanBuildFrom[From, T, To] {
         |       def apply(from: From) = b.apply() ; def apply() = b.apply()
         |    }
    breakOut: [From, T, To]
         |    (implicit b: scala.collection.generic.CanBuildFrom[Nothing,T,To])
         |    java.lang.Object with
         |    scala.collection.generic.CanBuildFrom[From,T,To]
    
    scala> val l = List(1, 2, 3)
    l: List[Int] = List(1, 2, 3)
    
    scala> val imp = l.map(_ + 1)(breakOut)
    imp: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4)
    
    scala> val arr: Array[Int] = l.map(_ + 1)(breakOut)
    imp: Array[Int] = Array(2, 3, 4)
    
    scala> val stream: Stream[Int] = l.map(_ + 1)(breakOut)
    stream: Stream[Int] = Stream(2, ?)
    
    scala> val seq: Seq[Int] = l.map(_ + 1)(breakOut)
    seq: scala.collection.mutable.Seq[Int] = ArrayBuffer(2, 3, 4)
    
    scala> val set: Set[Int] = l.map(_ + 1)(breakOut)
    seq: scala.collection.mutable.Set[Int] = Set(2, 4, 3)
    
    scala> val hashSet: HashSet[Int] = l.map(_ + 1)(breakOut)
    seq: scala.collection.mutable.HashSet[Int] = Set(2, 4, 3)
    

    You can see the return type is implicitly chosen by the compiler to best match the expected type. Depending on how you declare the receiving variable, you get different results.

    The following would be an equivalent way to specify a builder. Note in this case, the compiler will infer the expected type based on the builder's type:

    scala> def buildWith[From, T, To](b : Builder[T, To]) =
         |    new CanBuildFrom[From, T, To] {
         |      def apply(from: From) = b ; def apply() = b
         |    }
    buildWith: [From, T, To]
         |    (b: scala.collection.mutable.Builder[T,To])
         |    java.lang.Object with
         |    scala.collection.generic.CanBuildFrom[From,T,To]
    
    scala> val a = l.map(_ + 1)(buildWith(Array.newBuilder[Int]))
    a: Array[Int] = Array(2, 3, 4)
    

提交回复
热议问题