如果我在一个不可变的 Set
集合上调用 toSeq
,我得到 ArrayBuffer
.
scala> Set(1,2,3).toSeq // returns Seq[Int] = ArrayBuffer(1, 2, 3)
这让我感到惊讶 . 鉴于Scala强调使用不可变数据结构,我期望得到一个不可变的序列,如 Vector
或 List
而不是可变的 ArrayBuffer
. set元素的返回顺序当然应该是未定义的,但似乎没有任何语义上的原因,为什么这个顺序也应该是可变的 .
一般来说,我希望Scala操作总是产生不可变的结果,除非我明确请求一个可变的结果 . 这一直是我的假设,但这是一个不正确的,我实际上只花了一个小时调试一个问题,其中 ArrayBuffer
的意外存在导致 match
语句中的运行时错误 . 我的修复是将 Set(...).toSeq
更改为 Set(...).toList
,但这感觉就像一个黑客,因为我的应用程序没有任何需要特定列表的应用程序 .
让 Set(...).toSeq
返回一个可变对象是Scala实现中的一个缺陷,还是有一个我在这里误解的原则?
这是Scala 2.9.2 .
2 回答
Here是关于Seq是否应该表示immutable.Seq的最新线程 .
罗兰库恩:
可变varargs的例子相当偷偷摸摸 .
最近,
我同意这有点奇怪,但我不相信这是一个缺陷 . 首先,考虑一下:
Set.toSeq
的编译时类型是不
ArrayBuffer
恰好是返回对象的运行时类型(可能是因为Set.toSeq
添加到ArrayBuffer
然后只返回没有转换的那个) .所以,即使
toSeq
给你一个可变对象,你实际上也不能改变它(没有强制转换或模式匹配到ArrayBuffer
- 所以真正的"strange"部分是Scala允许你在任意类上进行模式匹配) . (你必须相信Set
不是一个公平的假设) .另一种看待它的方法是,可变类型只是比不可变类型更具体 . 或者,另一种说法是,每个可变对象也可以被视为一个不可变对象:一个不可变对象有一个getter,一个可变对象有一个getter和一个setter - 但它仍然有一个getter .
当然,这可能会被滥用:
但是,很多事情也是如此 .