gpt4 book ai didi

scala - 映射到相同类型时,Scala 的 map() 是否应该表现不同?

转载 作者:行者123 更新时间:2023-12-04 21:50:27 24 4
gpt4 key购买 nike

在 Scala Collections 框架中,我认为在使用 map() 时有一些违反直觉的行为。

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

第一类包含所包含元素的类型不变的所有转换。例如,它们是 filterpartitiondroptakespan 等。这些转换可以自由地调用 newBuilder 并重新创建与调用它们相同的集合类型,无论多么具体:过滤 List[Int] 始终可以返回一个 List[Int] ;过滤 BitSet (或 this article on the architecture of the collections framework 中描述的 RNA 示例结构)总是可以返回另一个 BitSet (或 RNA )。我们称它们为过滤转换。

第二类转换需要 CanBuildFrom s 更加灵活,因为包含的元素的类型可能会发生变化,因此可能无法重用集合本身的类型: BitSet 不能包含 String s; RNA 只包含 Base s。此类转换的示例是 mapflatMapcollectscanLeft++ 等。我们称它们为映射转换。

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

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, 2, 3, 4, 5)

scala> val set: Set[Int] = TreeSet(1,2,3,4,5) // static type != dynamic type
set: Set[Int] = TreeSet(1, 2, 3, 4, 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, 3, 4, 5, 6) // still fine

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

现在,我明白为什么会这样了。它被解释为 therethere 。简而言之:隐式 CanBuildFrom 是基于静态类型插入的,并且取决于其 def apply(from: Coll) 方法的实现,可能会也可能不会重新创建相同的集合类型。

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

那么我们将避免以下情况
for (i <- set) {
val x = i + 1
println(x)
}

不以与 TreeSet 相同的顺序打印 implicit sameTypeEvidence: A =:= B 的递增元素
for (i <- set; x = i + 1)
println(x)

所以:
  • 您认为按照所述更改映射转换的行为是否是个好主意?
  • 我严重忽视了哪些不可避免的警告?
  • 如何实现?

  • 我正在考虑类似 null 参数的东西,可能具有 implicit canReuseCalleeBuilderEvidence: B <:< A = null 的默认值(或者更确切地说是 CanBuildFrom ),它可以在运行时用于为 ojit_code 提供更多信息,而后者又可用于确定构建器的类型返回。

    最佳答案

    我又看了一遍,我认为你的问题不是由于 Scala 集合的特殊缺陷引起的,而是 TreeSet 缺少构建器。 .因为以下确实按预期工作:

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

    val vector = Vector(1,2,3,4,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 适本地准备了这样的伴侣。类,你可能会发现 mapfilter随心所欲地工作...?

    关于scala - 映射到相同类型时,Scala 的 map() 是否应该表现不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5678682/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com