Scala 2.8突破

Scala 2.8突破

斯卡拉2.8中有一个对象scala.collection.package.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()
 }

有人告诉我,这样做的结果是:

> import scala.collection.breakOut> val map : Map[Int,String] = List("London", "Paris").map(x => 
(x.length, x))(breakOut)map: Map[Int,String] = Map(6 -> London, 5 -> Paris)

这里发生什么事情?为什么breakOut被召唤作为论据敬我的List?


米脂
浏览 503回答 3
3回答

撒科打诨

答案是在…的定义上找到的。map:def&nbsp;map[B,&nbsp;That](f&nbsp;:&nbsp;(A)&nbsp;=>&nbsp;B)(implicit&nbsp;bf&nbsp;:&nbsp;CanBuildFrom[Repr,&nbsp;B,&nbsp;That])&nbsp;:&nbsp;That注意,它有两个参数。第一个是函数,第二个是隐式函数。如果不提供该隐式,Scala将选择最多。专一有一个。关于breakOut那么,breakOut?考虑为这个问题提供的示例,您需要一个字符串列表,将每个字符串转换为一个元组。(Int, String),然后产生一个Map从里面出来。最明显的方法就是产生一个中介List[(Int, String)]集合,然后转换它。鉴于map使用Builder要生成结果集合,不可以跳过中间层吗?List并将结果直接收集到Map?显然,是的。然而,要做到这一点,我们需要通过一个适当的CanBuildFrom到map,这正是breakOut的确如此。那么,让我们看看breakOut:def&nbsp;breakOut[From,&nbsp;T,&nbsp;To](implicit&nbsp;b&nbsp;:&nbsp;CanBuildFrom[Nothing,&nbsp;T,&nbsp;To])&nbsp;= &nbsp;&nbsp;new&nbsp;CanBuildFrom[From,&nbsp;T,&nbsp;To]&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;apply(from:&nbsp;From)&nbsp;=&nbsp;b.apply()&nbsp;;&nbsp;def&nbsp;apply()&nbsp;=&nbsp;b.apply() &nbsp;&nbsp;}请注意breakOut参数化,并且返回CanBuildFrom..碰巧,类型From,&nbsp;T和To已经被推断了,因为我们知道map期待CanBuildFrom[List[String], (Int, String), Map[Int, String]]..因此:From&nbsp;=&nbsp;List[String]T&nbsp;=&nbsp;(Int,&nbsp;String)To&nbsp;=&nbsp;Map[Int,&nbsp;String]最后,让我们检查一下breakOut本身。它是类型的CanBuildFrom[Nothing,T,To]..我们已经知道了所有这些类型,所以我们可以确定我们需要一个隐式的类型。CanBuildFrom[Nothing,(Int,String),Map[Int,String]]..但是否有这样的定义呢?让我们看看CanBuildFrom的定义:trait&nbsp;CanBuildFrom[-From,&nbsp;-Elem,&nbsp;+To]&nbsp;extends&nbsp;AnyRef所以CanBuildFrom是它的第一个类型参数的反变体。因为Nothing是一个底层(即它是所有事物的子类),这意味着任何类可用于替换Nothing.由于存在这样的构建器,Scala可以使用它来生成所需的输出。关于建筑商Scala集合库中的许多方法包括获取原始集合,以某种方式处理它(在map,转换每个元素),并将结果存储在一个新集合中。为了最大限度地重用代码,这种结果的存储是通过建筑商(scala.collection.mutable.Builder),它基本上支持两个操作:追加元素和返回结果集合。此结果集合的类型将取决于构建器的类型。因此,List建设者将返回List..Map建设者将返回Map等等。“公约”的执行情况map方法本身不需要考虑结果的类型:构建器负责处理它。另一方面,这意味着map需要以某种方式接待这个建筑工人。在设计Scala2.8集合时面临的问题是如何选择最佳的构建器。例如,如果我要写Map('a' -> 1).map(_.swap),我想要一个Map(1 -> 'a')背。另一方面,Map('a' -> 1).map(_._1)不能返回Map(它返回一个Iterable).创造出尽可能最好的东西的魔力Builder从已知类型的表达式中执行CanBuildFrom含蓄的。关于CanBuildFrom为了更好地解释正在发生的事情,我将给出一个示例,其中要映射的集合是Map而不是List..我会回到List后来。现在,考虑这两个表达式:Map(1&nbsp;->&nbsp;"one",&nbsp;2&nbsp;->&nbsp;"two")&nbsp;map&nbsp;Function.tupled(_&nbsp;->&nbsp;_.length)Map(1&nbsp;->&nbsp;"one",&nbsp;2&nbsp;->&nbsp;"two")&nbsp;map&nbsp;(_._2)第一个返回Map第二个返回Iterable..归还一个合适的收藏品的神奇之处在于CanBuildFrom..让我们考虑一下map再一次理解它。方法map继承自TraversableLike..它被参数化为B和That,并使用类型参数。A和Repr,它将类参数化。让我们一起看看这两个定义:全班TraversableLike定义为:trait&nbsp;TraversableLike[+A,&nbsp;+Repr]&nbsp;extends&nbsp;HasNewBuilder[A,&nbsp;Repr]&nbsp;with&nbsp;AnyRefdef&nbsp;map[B,&nbsp;That](f&nbsp;:&nbsp;(A)&nbsp;=>&nbsp;B)(implicit&nbsp;bf&nbsp;:&nbsp;CanBuildFrom [Repr,&nbsp;B,&nbsp;That])&nbsp;:&nbsp;That才能了解A和Repr来自,让我们考虑一下Map本身:trait&nbsp;Map[A,&nbsp;+B]&nbsp;extends&nbsp;Iterable[(A,&nbsp;B)]&nbsp;with&nbsp;Map[A,&nbsp;B]&nbsp;with&nbsp;MapLike[A,&nbsp;B,&nbsp;Map[A,&nbsp;B]]因为TraversableLike是由所有的性状继承的Map,&nbsp;A和Repr可以从他们中的任何一个继承下来。不过,最后一个得到了优先考虑。因此,按照不可变的定义Map以及与之相关的所有特征TraversableLike,我们有:trait&nbsp;Map[A,&nbsp;+B]&nbsp;extends&nbsp;Iterable[(A,&nbsp;B)]&nbsp;with&nbsp;Map[A,&nbsp;B]&nbsp;with&nbsp;MapLike[A,&nbsp;B,&nbsp;Map[A,&nbsp;B]]trait&nbsp;MapLike[A,&nbsp;+B,&nbsp;+This&nbsp;<:&nbsp;MapLike[A,&nbsp;B,&nbsp;This] with&nbsp;Map[A,&nbsp;B]]&nbsp;extends&nbsp;MapLike[A,&nbsp;B,&nbsp;This]trait&nbsp;MapLike[A,&nbsp;+B,&nbsp;+This&nbsp;<:&nbsp;MapLike[A,&nbsp;B,&nbsp;This]&nbsp;with&nbsp;Map[A,&nbsp;B]]&nbsp;extends&nbsp;PartialFunction[A,&nbsp;B]&nbsp;w ith&nbsp;IterableLike[(A,&nbsp;B),&nbsp;This]&nbsp;with&nbsp;Subtractable[A,&nbsp;This]trait&nbsp;IterableLike[+A,&nbsp;+Repr]&nbsp;extends&nbsp;Equals&nbsp;with&nbsp;TraversableLike[A,&nbsp;Repr]trait&nbsp;T raversableLike[+A,&nbsp;+Repr]&nbsp;extends&nbsp;HasNewBuilder[A,&nbsp;Repr]&nbsp;with&nbsp;AnyRef如果您传递的类型参数Map[Int, String]在整个链上,我们发现类型传递给TraversableLike,因此,被map,是:A&nbsp;=&nbsp;(Int,String)Repr&nbsp;=&nbsp;Map[Int,&nbsp;String]回到示例,第一个映射正在接收一个类型为((Int, String)) => (Int, Int)而第二个映射正在接收一个类型的函数。((Int, String)) => String..我使用双括号来强调它是被接收的元组,因为这是A就像我们看到的。有了这些信息,让我们考虑其他类型。map&nbsp;Function.tupled(_&nbsp;->&nbsp;_.length):B&nbsp;=&nbsp;(Int,&nbsp;Int)map&nbsp;(_._2):B&nbsp;=&nbsp;String我们可以看到第一个返回的类型map是Map[Int,Int],第二个是Iterable[String]..望着map的定义,很容易看出这些是That..但它们是从哪里来的呢?如果我们查看所涉及的类的伴生对象,就会看到一些提供它们的隐式声明。论客体Map:implicit&nbsp;def&nbsp;&nbsp;canBuildFrom&nbsp;[A,&nbsp;B]&nbsp;:&nbsp;CanBuildFrom[Map,&nbsp;(A,&nbsp;B),&nbsp;Map[A,&nbsp;B]]以及在物体上Iterable,其类由Map:implicit&nbsp;def&nbsp;&nbsp;canBuildFrom&nbsp;[A]&nbsp;:&nbsp;CanBuildFrom[Iterable,&nbsp;A,&nbsp;Iterable[A]]这些定义为参数化提供了工厂。CanBuildFrom.Scala将选择最具体的隐式可用。在第一个案例中,它是第一个CanBuildFrom..在第二种情况下,由于第一种不匹配,它选择了第二种。CanBuildFrom.回到问题上让我们看看这个问题的代码,List和map的定义(再次)以查看如何推断类型:val&nbsp;map&nbsp;:&nbsp;Map[Int,String]&nbsp;=&nbsp;List("London",&nbsp;"Paris").map(x&nbsp;=>&nbsp;(x.length,&nbsp;x))(breakOut)sealed&nbsp;abstract&nbsp;class&nbsp;List[+A]&nbsp;extends&nbsp;LinearSeq[A]&nbsp; with&nbsp;Product&nbsp;with&nbsp;GenericTraversableTemplate[A,&nbsp;List]&nbsp;with&nbsp;LinearSeqLike[A,&nbsp;List[A]]trait&nbsp;LinearSeqLike[+A,&nbsp;+Repr&nbsp;<:&nbsp;LinearSeqLike[A,&nbsp;Repr]]&nbsp; extends&nbsp;SeqLike[A,&nbsp;Repr]trait&nbsp;SeqLike[+A,&nbsp;+Repr]&nbsp;extends&nbsp;IterableLike[A,&nbsp;Repr]trait&nbsp;IterableLike[+A,&nbsp;+Repr]&nbsp;extends&nbsp;Equals&nbsp;with&nbsp;TraversableL ike[A,&nbsp;Repr]trait&nbsp;TraversableLike[+A,&nbsp;+Repr]&nbsp;extends&nbsp;HasNewBuilder[A,&nbsp;Repr]&nbsp;with&nbsp;AnyRefdef&nbsp;map[B,&nbsp;That](f&nbsp;:&nbsp;(A)&nbsp;=>&nbsp;B)(implicit&nbsp;bf&nbsp;:&nbsp; CanBuildFrom[Repr,&nbsp;B,&nbsp;That])&nbsp;:&nbsp;That类型List("London", "Paris")是List[String],所以类型A和Repr定义在TraversableLike是:A&nbsp;=&nbsp;StringRepr&nbsp;=&nbsp;List[String]类型(x => (x.length, x))是(String) => (Int, String),所以B是:B&nbsp;=&nbsp;(Int,&nbsp;String)最后一个未知的类型,That的结果的类型。map,我们已经有了:val&nbsp;map&nbsp;:&nbsp;Map[Int,String]&nbsp;=所以,That&nbsp;=&nbsp;Map[Int,&nbsp;String]这意味着breakOut必须返回CanBuildFrom[List[String], (Int, String), Map[Int, String]].

Smart猫小萌

我想在丹尼尔回答的基础上再接再厉。这是非常彻底的,但正如评论中所指出的,它并没有解释什么是突破。摘自Re:支持显式构建器(2009-10-23年),以下是我认为的突破:它向编译器建议隐式选择哪个Builder(本质上它允许编译器选择它认为最适合这种情况的工厂)。例如,请参见以下内容:scala>&nbsp;import&nbsp;scala.collection.generic._import&nbsp;scala.collection.generic._ scala>&nbsp;import&nbsp;scala.collection._import&nbsp;scala.collection._ scala>&nbsp;import&nbsp;scala.collection.mutable._import&nbsp;scala.collection.mutable._ scala>scala>&nbsp;def&nbsp;breakOut[From,&nbsp;T,&nbsp;To](implicit&nbsp;b&nbsp;:&nbsp;CanBuildFrom[Nothing,&nbsp;T,&nbsp;To])&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;CanBuildFrom[From,&nbsp;T,&nbsp;To]&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;apply(from:&nbsp;From)&nbsp;=&nbsp;b.apply()&nbsp;;&nbsp;def&nbsp;apply()&nbsp;=&nbsp;b.apply() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;}breakOut:&nbsp;[From,&nbsp;T,&nbsp;To] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;(implicit&nbsp;b:&nbsp;scala.collection.generic.CanBuildFrom[Nothing,T,To]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;java.lang.Object&nbsp;with &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;scala.collection.generic.CanBuildFrom[From,T,To]scala>&nbsp;val&nbsp;l&nbsp;=&nbsp;List(1,&nbsp;2,&nbsp;3)l:&nbsp;List[Int]&nbsp;=&nbsp;List(1,&nbsp;2,&nbsp;3)scala>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;imp&nbsp;=&nbsp;l.map(_&nbsp;+&nbsp;1)(breakOut)imp:&nbsp;scala.collection.immutable.IndexedSeq[Int]&nbsp;=&nbsp;Vector(2,&nbsp;3,&nbsp;4)scala>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;arr:&nbsp;Array[Int]&nbsp;=&nbsp;l.map(_&nbsp;+&nbsp;1)(breakOut)imp:&nbsp;Array[Int]&nbsp;=&nbsp;Array(2,&nbsp;3,&nbsp;4)scala>&nbsp;val&nbsp;stream:&nbsp;Stream[Int]&nbsp;=&nbsp;l. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map(_&nbsp;+&nbsp;1)(breakOut)stream:&nbsp;Stream[Int]&nbsp;=&nbsp;Stream(2,&nbsp;?)scala>&nbsp;val&nbsp;seq:&nbsp;Seq[Int]&nbsp;=&nbsp;l.map(_&nbsp;+&nbsp;1)(breakOut)seq:&nbsp;scala.col &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lection.mutable.Seq[Int]&nbsp;=&nbsp;ArrayBuffer(2,&nbsp;3,&nbsp;4)scala>&nbsp;val&nbsp;set:&nbsp;Set[Int]&nbsp;=&nbsp;l.map(_&nbsp;+&nbsp;1)(breakOut)seq:&nbsp;scala.collection.mutabl &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Set[Int]&nbsp;=&nbsp;Set(2,&nbsp;4,&nbsp;3)scala>&nbsp;val&nbsp;hashSet:&nbsp;HashSet[Int]&nbsp;=&nbsp;l.map(_&nbsp;+&nbsp;1)(breakOut)seq:&nbsp;scala.collection.mutable.HashSet[Int] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;Set(2,&nbsp;4,&nbsp;3)您可以看到返回类型是由编译器隐式选择的,以最佳匹配预期类型。根据声明接收变量的方式,可以得到不同的结果。下面是指定构建器的等效方法。注在这种情况下,编译器将根据构建器的类型推断预期的类型:scala>&nbsp;def&nbsp;buildWith[From,&nbsp;T,&nbsp;To](b&nbsp;:&nbsp;Builder[T,&nbsp;To])&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;CanBuildFrom[From,&nbsp;T,&nbsp;To]&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;apply(from:&nbsp;From)&nbsp;=&nbsp;b&nbsp;;&nbsp;def&nbsp;apply()&nbsp;=&nbsp;b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;}buildWith:&nbsp;[From,&nbsp;T,&nbsp;To] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;(b:&nbsp;scala.collection.mutable.Builder[T,To]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;java.lang.Object&nbsp;with &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;scala.collection.generic.CanBuildFrom[From,T,To]scala>&nbsp;val&nbsp;a&nbsp;=&nbsp;l.map(_&nbsp;+&nbsp;1)(buildWith(Array.newBuilder[Int]))a: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Array[Int]&nbsp;=&nbsp;Array(2,&nbsp;3,&nbsp;4)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python