gpt4 book ai didi

当静态类型为 Map 时,Scala SortedMap.map 方法返回未排序的 map

转载 作者:行者123 更新时间:2023-12-04 12:34:49 26 4
gpt4 key购买 nike

我在使用 Scala 的 SortedMap[A,B] 时遇到了一些未经授权的奇怪现象。如果我声明对 SortedMap[A,B] "a"的引用是 Map[A,B] 类型,那么对 "a"的映射操作将产生一个未排序的映射实现。

例子:

import scala.collection.immutable._

object Test extends App {
val a: Map[String, String] = SortedMap[String, String]("a" -> "s", "b" -> "t", "c" -> "u", "d" -> "v", "e" -> "w", "f" -> "x")
println(a.getClass+": "+a)

val b = a map {x => x} // identity
println(b.getClass+": "+b)
}

上面的输出是:

class scala.collection.immutable.TreeMap: Map(a -> s, b -> t, c -> u, d -> v, e -> w, f -> x)
class scala.collection.immutable.HashMap$HashTrieMap: Map(e -> w, f -> x, a -> s, b -> t, c -> u, d -> v)



身份转换前后键/值对的顺序不一样。

奇怪的是,从“a”中删除类型声明会使这个问题消失。这在一个玩具示例中很好,但会使 SortedMap[A,B] 无法用于传递给需要 Map[A,B] 参数的方法。

一般来说,我希望诸如“map”和“filter”之类的高阶函数不会改变它们所应用的集合的基本属性。

有谁知道为什么“ map ”会这样?

最佳答案

map方法和大多数收集方法一样,不是专门为 SortedMap 定义的。 .它在更高级别的类(TraversableLike)上定义,并使用“构建器”将映射结果转换为正确的返回类型。

那么它如何决定“正确”的返回类型是什么?好吧,它试图给你返回它开始时的返回类型。当你告诉 Scala 你有一个 Map[String,String]并询问map ,那么构建器必须弄清楚如何“构建”返回的类型。既然你告诉 Scala 输入是 Map[String,String] , builder 决定 build 一个 Map[String,String]为你。 builder 不知道您想要 SortedMap ,所以它不给你一个。

当您离开 Map[String,String] 时它起作用的原因类型注释是 Scala 推断 a 的类型是 SortedMap[String,String] .因此,当您调用 map ,您在 SortedMap 上调用它, 并且构建者知道构造一个 SortedMap为返回。

至于您断言方法不应改变“基本属性”,我认为您从错误的角度看待它。这些方法将始终为您返回一个符合您指定类型的对象。它是定义构建器行为的类型,而不是底层实现。当你这样想的时候,它是形成方法应该如何表现的契约的类型。

为什么我们想要这个?

为什么这是首选行为?让我们看一个具体的例子。假设我们有一个 SortedMap[Int,String]

val sortedMap = SortedMap[Int, String](1 -> "s", 2 -> "t", 3 -> "u", 4 -> "v")

如果我是 map使用修改键的功能对其进行修改,我冒着在键发生冲突时丢失元素的风险:
scala> sortedMap.map { case (k, v) => (k / 2, v) }
res3: SortedMap[Int,String] = Map(0 -> s, 1 -> u, 2 -> v)

但是,嘿,没关系。这是一个 Map毕竟,我知道这是一个 Map ,所以我应该期待这种行为。

现在假设我们有一个接受 Iterable 的函数。对数:
def f(iterable: Iterable[(Int, String)]) = 
iterable.map { case (k, v) => (k / 2, v) }

由于该函数与 Map 无关s,如果这个函数的结果比输入的元素少,那将是非常令人惊讶的。毕竟, mapIterable应该产生每个元素的映射版本。但是一个 MapIterable对,所以我们可以将它传递给这个函数。那么当我们这样做时,Scala 会发生什么?
scala> f(sortedMap)
res4: Iterable[(Int, String)] = List((0,s), (1,t), (1,u), (2,v))

看那个!没有丢失任何元素!换句话说,Scala 不会因为违反我们对 map 的预期而感到惊讶。在 Iterable应该管用。如果生成器改为尝试生成 SortedMap基于输入是 SortedMap 的事实, 那么我们的函数 f会产生令人惊讶的结果,这会很糟糕。

所以这个故事的寓意是:使用类型告诉集合框架如何处理您的数据。如果您希望您的代码能够预期 map 已排序,则应将其键入为 SortedMap .

关于当静态类型为 Map 时,Scala SortedMap.map 方法返回未排序的 map ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12629260/

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