了解GenericTraversableTemplate和其他Scala收集内部
我和一个熟悉的Kotlin,Clojure和
Java8粉丝的朋友交换了电子邮件,问他为什么不Scala.他提供了很多原因(Scala太学术,功能太多,不是我第一次听到这个,我觉得这很主观)
但他最大的痛点就是一个例子,他不喜欢一个他不能理解基本数据结构实现的语言,他以LinkedList为例. 我看了一下scala.collection.LinkedList并计算了我理解或有些理解的东西. > CanBuildFrom – 经过一番努力,我得到它,键入类,而不是最长的自杀笔记 但是我开始盯着这些 > GenericTraversableTemplate – 现在我正在抓我的头 有理解这个的人可以在LinkedList的上下文中解释GenericTraversableTemplate SeqFactory和GenericCompanion吗?他们是什么,对他们的最终用户有什么影响(例如我确定他们在那里有一个很好的理由,这是什么原因?) 他们在那里有实际的理由吗?还是可以简化的抽象级别? 我喜欢Scala系列,因为我不必了解内部能够有效地使用它们.我不介意复杂的实现,如果它帮助我保持我的使用更简单.例如如果我有能力使用它来编写更干净的更优雅的代码,我不介意支付一个复杂的图书馆的价格.但是一定要更好地了解它. [1] – Is the Scala 2.8 collections library a case of “the longest suicide note in history”? 解决方法
我将尝试从随机行人角度来描述这些概念(我从来没有为Scala收藏库贡献一条线,所以如果我错了就不要打我太难).
由于LinkedList现在已被弃用,因为Maps提供了一个更好的例子,我将使用TreeMap作为示例. CanBuildFrom 动机是这样的:如果我们采取一个TreeMap [Int,Int]并将其映射 case (x,y) => (2 * x,y * y * 0.3d) 我们得到TreeMap [Int,Double].这种类型的安全本身就已经解释了必要性 case (x,y) => x 我们获得一个Iterable [Int](更准确地说:一个List [Int]),这不再是一个Map,容器的类型已经改变了.这是CBF发挥作用的地方: CanBuildFrom[This,X,That] 可以看作是一种“类型功能”,告诉我们:如果我们映射一个类型的集合 CanBuildFrom[TreeMap[_,_],(X,Y),TreeMap[X,Y]] 在第二种情况下,Iterable[X]] 所以我们总是得到正确的容器类型.这个模式很普通. foo[X1,...,Xn](x1: X1,xn: Xn): Y 其中结果类型Y取决于X1,…,Xn,可以引入隐式参数 foo[X1,....,Y](x1: X1,xn: Xn)(implicit CanFooFrom[X1,Y]): Y 然后定义类型级别的函数X1,Xn→> Y分段提供多个 LinkedListLike 在类定义中,我们看到如下: TreeMap[A,B] extends SortedMap[A,B] with SortedMapLike[A,B,TreeMap[A,B]] 这是Scala表达所谓的F边界多态性的方式. def withoutHead = this.remove(this.head) 如果我们将实现移到SortedMap [A??,B]本身,那么我们可以做的最好的就是: def withoutHead: SortedMap[A,B] = this.remove(this.head) 但这是我们可以得到的最具体的结果类型吗?不,太模糊了. trait SortedMapLike[A,Repr <: SortedMap[A,B]] { ... def withoutHead: Repr = this.remove(this.head) } 现在因为TreeMap [A??,B]扩展了SortedMapLike [A,TreeMap [A??,B]],结果类型 GenericTraversableTemplate 类型是:GenericTraversableTemplate [A,CC [X]< ;: GenTraversable [X]] 据我所知,这只是一个提供实现的特质 东西像foldLeft,减少,存在不在这里,因为这些方法只关心内容类型,而不是容器类型. 像flatMap这样的东西不在这里,因为容器类型可以改变(再次,CBF的). 为什么它是一个单独的特质,它有存在的根本原因吗? GenericCompanion 这只是一个实现一些常见的基本功能的抽象类 例如,有一些方法适用于使用某些类型A的varargs并返回类型为CC [A]的集合: Array(1,2,3,4) // calls Array.apply[A](elems: A*) on the companion object List(1,4) // same for List 实现非常简单,就像这样: def apply[A](varargs: A*): CC[A] = { val builder = newBuilder[A] for (arg <- varargs) builder += arg builder.result() } 这对于数组和列表和TreeMaps以及几乎所有其他内容来说显然是一样的,除了像Bitset这样的“不规则集合”.所以这只是大多数伴侣对象的共同祖先类中的常用功能.没什么特别的. SeqFactory 与GenericCompanion类似,但这次更具体针对Sequences. 几句俗话 一般来说:我不认为应该尝试了解这个图书馆的每一个特征.相反,应该尝试整体看图书馆.作为一个整体,它有一个非常有趣的建筑.而在我个人看来,它实际上是一个非常美观的软件,但是一个人必须盯着它一段时间(并尝试重新实现整个架构模式几次)来掌握它.另一方面,例如CBF是一种“设计模式”,显然应该在这种语言的继承者中消除.整个故事与隐含的CBF的范围仍然对我来说总是噩梦.但是,许多事情起初似乎完全不可思议,而且几乎总是以一个顿悟(这是非常具体的Scala)结束:对于大多数其他语言,这种斗争通常以思想结束“这是一个完整的白痴的作者”) . (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |