【发布时间】:2010-01-23 13:34:57
【问题描述】:
为什么在 Scala 中不推荐使用 List 的 + 运算符?
http://www.scala-lang.org/docu/files/api/scala/List.html#%2B%28B%29
【问题讨论】:
标签: list scala operator-overloading deprecated
为什么在 Scala 中不推荐使用 List 的 + 运算符?
http://www.scala-lang.org/docu/files/api/scala/List.html#%2B%28B%29
【问题讨论】:
标签: list scala operator-overloading deprecated
好问题,所以我在 Odersky 等人的书中查找了它。它说以下内容(希望在这里引用它不是侵犯版权;-)):
List 类不提供追加操作,因为追加到列表所需的时间随着列表的大小线性增长,而在前面添加 :: 需要固定时间。如果您想通过附加元素来构建列表,您的选择是预先添加它们,然后当您完成调用 reverse;或使用ListBuffer,一个提供追加操作的可变列表,完成后调用toList。
据我了解 FP,添加到列表比添加更常见,至少在纯函数式语言中是这样。我只能假设 Scala 的设计者添加了 + 运算符是为了方便 Java 开发人员使用 add() 进行附加,然后再考虑。
【讨论】:
O(1) 和一个很小的常数因子,附加是 O(n) 和一个相当大的 c。
O(n) 的复杂性是由于需要复制列表,而这是由于需要具有不可变列表。仅使用不可变数据是函数式编程语言的标志。所以我仍然会说这是一个FP的事情。在 Java 的列表类型中,或者例如C++ 中的std::list::push_back 附加有O(1)。
它已于 2008 年 5 月在 revision 15071 中被弃用,并带有以下消息:
弃用所有有问题的 + 方法,并删除那些从未出现在版本中的方法。
我希望这是为了避免与 StringAdd#+ 产生歧义。下面比较 2.7.6 和 2.8.0 Beta 之间的区别:
Welcome to Scala version 2.7.6.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
Type in expressions to have them evaluated.
Type :help for more information.
scala> List(1) + 2
warning: there were deprecation warnings; re-run with -deprecation for details
res0: List[Int] = List(1, 2)
scala> List(1) + "2"
warning: there were deprecation warnings; re-run with -deprecation for details
res1: List[Any] = List(1, 2)
在 2.8 中,该方法已被删除,您会得到:
Welcome to Scala version 2.8.0.Beta1-RC8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
Type in expressions to have them evaluated.
Type :help for more information.
scala> List(1) + 2
<console>:5: error: type mismatch;
found : Int(2)
required: String
List(1) + 2
^
scala> List(1) + "2"
res1: java.lang.String = List(1)2
更新
在 scala 用户列表中,Martin Odersky 指出:
找出真正不好的地方 List#+,考虑你的期望 产生以下内容:
List(1, 2, 3) + " 是正确的 结果”
?
oxbow_lakes 补充说 - 我花了一段时间才解开这个神秘的评论,但我认为重点是它会违反 + 运算符所暗示的类型的交换性。即a + b的类型应该和b + a的类型一致
更新 Martin Odersky 的澄清:
你会期待什么
List(1, 2, 3) + "是正确的结果"
生产?我希望有一个字符串: “List(1, 2, 3) 是正确的结果”。
使用 2.7 样式的 List.+,您会得到 a List[Any], List(1, 2, 3, "是 正确的结果”)。
我将其归类为一个糟糕的惊喜。在 总结,一个人永远不应该有 + 对元素类型协变的集合的方法。套 而且地图是不变的,这就是为什么 他们可以有一个 + 方法。就是这样 相当精致和凌乱。我们会 如果我们不尝试的话会更好 重复 Java 的 + for String 级联。但是当 Scala 得到 设计的想法是保持 基本上所有的 Java 表达式 语法,包括字符串 +。它是 现在改变它为时已晚。
【讨论】:
它不是可交换的,并且在列表中特别次优。此外,可变集合和不可变集合之间的行为不同。在 Scala 2.8 上,您有以下内容:
element +: sequence // prepend
sequence :+ element // append
sequenece ++ sequence // concatenate
可变/不可变的事情还没有完全解决。作为第一步,一堆方法被弃用,但如果没有一个弃用期,就无法更改或彻底删除它们。
【讨论】:
+: 和 :+ 并不是人们期望可交换的众所周知的运算符。
如果你关注this thread,你会发现它可能是因为性能问题。
一般应安排
List构造,以免追加。 Scala 的 List 是一个不可变的单链表,因此附加到它的末尾是一个 O(n) 操作。
ListA ::: ListB是右关联的,运行时间与 ListA 的长度成正比 'a ::: b' 是 /prepend/ 操作,在O(a.length)时间运行
【讨论】: