Kev*_*ght 60 collections scala
注意:这是一个常见问题解答,具体问我所以我可以自己回答,因为这个问题似乎经常出现,我想把它放在一个可以(希望)通过搜索很容易找到的地方
根据我在这里的回答评论提示
例如:
"abcde" map {_.toUpperCase} //returns a String
"abcde" map {_.toInt} // returns an IndexedSeq[Int]
BitSet(1,2,3,4) map {2*} // returns a BitSet
BitSet(1,2,3,4) map {_.toString} // returns a Set[String]
查看scaladoc,所有这些都使用了map继承自的操作TraversableLike,那么为什么它始终能够返回最具体的有效集合呢?甚至String,它map通过隐式转换提供.
Kev*_*ght 79
Scala系列是聪明的东西......
收集库的内部是Scala土地上更高级的主题之一.它涉及更高级的类型,推理,方差,含义和CanBuildFrom机制 - 所有这些都使其从面向用户的角度来看具有令人难以置信的通用性,易用性和强大性.从API设计者的角度理解它并不是一个初学者要采取的轻松任务.
另一方面,你真的需要在这个深度上使用集合是非常罕见的.
那么让我们开始......
随着Scala 2.8的发布,集合库被完全重写以删除重复,许多方法被移动到一个地方,以便持续维护和添加新的收集方法将更容易,但它也使层次结构更难了解.
就拿List例如,这从继承(反过来)
LinearSeqOptimisedGenericTraversableTemplateLinearSeqSeqSeqLikeIterableIterableLikeTraversableTraversableLikeTraversableOnce这是非常少数!为什么这个深层次的层次?XxxLike简单地忽略这些特征,该层次结构中的每个层都添加了一些功能,或者提供了更优化的继承功能版本(例如,通过索引获取元素Traversable需要组合drop和head操作,对索引序列非常低效) ).在可能的情况下,所有功能都被推送到层次结构尽可能远的地方,最大化可以使用它的子类的数量并删除重复.
map就是这样一个例子.该方法实现在TraversableLike(尽管这些XxxLike特征仅对图书馆设计者来说确实存在,因此它通常被认为是一种Traversable用于大多数意图和目的的方法 - 我将很快谈到这一部分),并且被广泛继承.可以在某个子类中定义优化版本,但它仍然必须符合相同的签名.考虑以下用法map(也在问题中提到):
"abcde" map {_.toUpperCase} //returns a String
"abcde" map {_.toInt} // returns an IndexedSeq[Int]
BitSet(1,2,3,4) map {2*} // returns a BitSet
BitSet(1,2,3,4) map {_.toString} // returns a Set[String]
在每种情况下,输出尽可能与输入的类型相同.当它是不可能的,输入型的超检查直到一个发现确实提供了一个有效的返回类型.做到这一点需要做很多工作,特别是当你认为它String甚至不是一个集合时,它只能隐含地转换为一个集合.
那怎么办?
这个难题的一半是XxxLike特征(我确实说过我会得到它们......),其主要功能是采用Repr类型参数("表示"的缩写),以便它们知道真正的子类实际存在经营.因此,例如与类型参数TraversableLike相同Traversable,但是在Repr类型参数上进行抽象.然后在拼图的后半部分使用该参数; 所述CanBuildFrom捕获源集合型类型,目标元素类型和目标集合类型由收集-变换操作中.
通过一个例子来解释更容易!
BitSet定义了一个这样的隐式实例CanBuildFrom:
implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
编译时BitSet(1,2,3,4) map {2*},编译器将尝试隐式查找CanBuildFrom[BitSet, Int, T]
这是一个聪明的部分......范围中只有一个与前两个类型参数匹配的隐式.第一个参数是Repr由XxxLike特征捕获的,第二个参数是元素类型,由当前集合特征(例如Traversable)捕获.map然后,该操作也使用类型进行参数化,该类型T是基于CanBuildFrom隐式定位的实例的第三类型参数来推断的.BitSet在这种情况下.
所以前两个类型参数CanBuildFrom是输入,用于隐式查找,第三个参数是输出,用于推理.
CanBuildFrom在BitSet因此匹配两种类型BitSet和Int,所以查找会成功,并推断返回类型也将是BitSet.
编译时BitSet(1,2,3,4) map {_.toString},编译器将尝试隐式查找CanBuildFrom[BitSet, String, T].对于BitSet中的隐式,这将失败,因此编译器接下来会尝试其超类Set- 这包含隐式:
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A]
它匹配,因为科尔是真实初始化是一种类型的别名BitSet时,BitSet从派生Set.在A将匹配任何东西,因为canBuildFrom是参数与类型A,在这种情况下,它推断是String......由此产生的返回类型Set[String].
因此,要正确实现集合类型,您不仅需要提供正确的类型隐式CanBuildFrom,还需要确保将该集合的具体类型作为Repr参数提供给正确的父特征(例如,将MapLike在子类化的情况下Map).
String因为它map通过隐式转换提供了一点点复杂.隐式转换是指最终派生的StringOps子类- 作为类型参数.StringLike[String]TraversableLike[Char,String]StringRepr
还有一个CanBuildFrom[String,Char,String]范围,以便编译器知道在将a的元素映射String到Chars时,返回类型也应该是一个字符串.从这一点开始,使用相同的机制.
Scala Collections在线页面的体系结构有一个详细的解释,面向基于2.8集合设计创建新集合的实际方面.
引用:
"如果你想集成一个新的集合类,那么需要做些什么,这样才能从正确类型的所有预定义操作中获益?在接下来的几页中,你将会看到两个这样做的例子."
它使用例如用于编码RNA序列的集合和用于Patricia trie的集合.查找" 处理地图和朋友"部分,了解如何返回相应的集合类型.
| 归档时间: | 
 | 
| 查看次数: | 4125 次 | 
| 最近记录: |