加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala的map()在映射到相同类型时是否应该有不同的行为?

发布时间:2020-12-16 18:29:27 所属栏目:安全 来源:网络整理
导读:在 Scala Collections框架中,我认为使用map()时会有一些违反直觉的行为. 我们可以区分(不可变)集合上的两种转换.那些实现调用newBuilder来重新创建生成的集合的人,以及那些通过隐式CanBuildFrom来获取构建器的人. 第一个类别包含所有转换,其中包含的元素的类
在 Scala Collections框架中,我认为使用map()时会有一些违反直觉的行为.

我们可以区分(不可变)集合上的两种转换.那些实现调用newBuilder来重新创建生成的集合的人,以及那些通过隐式CanBuildFrom来获取构建器的人.

第一个类别包含所有转换,其中包含的元素的类型不会更改.它们是,例如,filter,partition,drop,take,span等.这些转换可以自由调用newBuilder并重新创建与它们被调用的相同的集合类型,无论具体如何:过滤List [Int] ]总是可以返回List [Int];过滤BitSet(或this article on the architecture of the collections framework中描述的RNA示例结构)总是可以返回另一个BitSet(或RNA).我们称之为过滤转换.

第二类转换需要CanBuildFroms更灵活,因为包含的元素的类型可能会改变,因此,集合本身的类型可能无法重用:BitSet不能包含字符串; RNA仅含有碱基.这种转换的例子有map,flatMap,collect,scanLeft等.让我们称它们为映射转换.

现在这是讨论的主要问题.无论集合的静态类型是什么,所有过滤转换都将返回相同的集合类型,而映射操作返回的集合类型可能会因静态类型而异.

scala> import collection.immutable.TreeSet
import collection.immutable.TreeSet

scala> val treeset = TreeSet(1,2,3,4,5) // static type == dynamic type
treeset: scala.collection.immutable.TreeSet[Int] = TreeSet(1,5)

scala> val set: Set[Int] = TreeSet(1,5) // static type != dynamic type
set: Set[Int] = TreeSet(1,5)

scala> treeset.filter(_ % 2 == 0)
res0: scala.collection.immutable.TreeSet[Int] = TreeSet(2,4) // fine,a TreeSet again

scala> set.filter(_ % 2 == 0)    
res1: scala.collection.immutable.Set[Int] = TreeSet(2,4) // fine

scala> treeset.map(_ + 1)        
res2: scala.collection.immutable.SortedSet[Int] = TreeSet(2,5,6) // still fine

scala> set.map(_ + 1)    
res3: scala.collection.immutable.Set[Int] = Set(4,6,3) // uh?!

现在,我理解为什么这样的工作原理.它解释为there和there.简而言之:隐式CanBuildFrom是基于静态类型插入的,并且,根据其def apply(from:Coll)方法的实现,可能会也可能不会重新创建相同的集合类型.

现在我的唯一观点是,当我们知道我们正在使用映射操作产生具有相同元素类型的集合(编译器可以静态地确定)时,我们可以模仿过滤变换的工作方式并使用集合的本机构建器.我们可以在映射到Ints时重用BitSet,创建具有相同排序的新TreeSet等.

然后我们会避免在哪些情况下

for (i <- set) {
  val x = i + 1
  println(x)
}

不按照与之相同的顺序打印TreeSet的递增元素

for (i <- set; x = i + 1)
  println(x)

所以:

>您是否认为如上所述更改映射转换的行为是个好主意?
>我忽略了哪些不可避免的警告?
>怎么可以实施?

我正在考虑类似隐式sameTypeEvidence:A =:= B参数,可能默认值为null(或者更确切地说是隐式canReuseCalleeBuilderEvidence:B<:< A = null),可以在运行时使用有关CanBuildFrom的更多信息,而这些信息又可用于确定要返回的构建器的类型.

解决方法

我再次查看它,我认为您的问题不是由Scala集合的特定缺陷引起的,而是TreeSet缺少的构建器.因为以下内容按预期工作:

val list = List(1,5)
val seq1: Seq[Int] = list
seq1.map( _ + 1 ) // yields List

val vector = Vector(1,5)
val seq2: Seq[Int] = vector
seq2.map( _ + 1 ) // yields Vector

所以原因是TreeSet缺少一个专门的伴侣对象/构建器:

seq1.companion.newBuilder[Int]    // ListBuffer
seq2.companion.newBuilder[Int]    // VectorBuilder
treeset.companion.newBuilder[Int] // Set (oops!)

所以我的猜测是,如果你为你的RNA类适当提供这样的伴侣,你可能会发现地图和过滤器都可以按你的意愿工作……?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读