43

这是这个问题的反面:为什么字符串在 Java 和 .NET 中不能是可变的?

在 Ruby 中做出这个选择仅仅是因为操作(追加等)在可变字符串上很有效,还是有其他原因?

(如果只是效率,那似乎很奇怪,因为 Ruby 的设计似乎并没有高度重视促进高效实现。)

4

2 回答 2

32

正如您所指出的,这符合 Ruby 的设计。不可变字符串比可变字符串更有效 - 复制更少,因为字符串被重复使用 - 但使程序员的工作更加困难。将字符串视为可变的很直观 - 您可以将它们连接在一起。为了解决这个问题,Java 默默地翻译连接(通过+两个字符串的连接(通过)转换为 StringBuffer 对象的使用,我相信还有其他这样的技巧。Ruby 选择默认情况下以牺牲性能为代价使字符串可变。

Ruby 还有许多破坏性方法,例如String#upcase!依赖于可变字符串的方法。

另一个可能的原因是 Ruby 受到 Perl 的启发,而 Perl 恰好使用可变字符串。

Ruby 有符号和冻结字符串,它们都是不可变的。作为额外的奖励,每个可能的字符串值都保证符号是唯一的。

于 2010-04-09T15:03:45.863 回答
5

这些是我的意见,不是马茨的。出于这个答案的目的,当我说一种语言具有“不可变字符串”时,这意味着它的所有字符串都是不可变的,即没有办法创建一个可变的字符串。

  1. “不可变字符串”设计将字符串视为标识符(例如,作为哈希键和其他 VM 内部用途)和数据存储结构. 这个想法是标识符可变是危险的。对我来说,这听起来像是对单一职责的违反。在 Ruby 中,我们有标识符的符号,因此字符串可以自由地充当数据存储。Ruby 确实允许字符串作为哈希键,但我认为程序员很少将字符串存储到变量中,将其用作哈希键,然后修改字符串。在程序员的心目中,存在(或应该)分离字符串的两种用法。通常,用作哈希键的字符串是文字字符串,因此它被变异的可能性很小。使用字符串作为哈希键与使用两个字符串的数组作为哈希键没有太大区别。只要你的头脑很好地掌握了你使用什么作为钥匙,那么就没有问题。

  2. 从认知简单性的角度来看,将字符串作为数据存储很有用。只需考虑 Java 及其StringBuffer. 这是一个额外的数据结构(在一个已经很大且通常不直观的标准库中),如果您尝试执行字符串操作,例如在另一个字符串的某个索引处插入一个字符串,则必须对其进行管理。因此,一方面,Java 认识到需要进行这类操作,但由于不可变字符串暴露给程序员,他们不得不引入另一种结构,因此这些操作仍然是可能的,而无需我们重新发明轮子。这给程序员带来了额外的认知负担。

  3. 在 Python 中,似乎最简单的插入方法是在插入点之前和之后获取子字符串,然后将它们连接到要插入的字符串周围。我想他们可以很容易地向标准库中添加一个插入和返回新字符串的方法。但是,如果调用该方法insert,初学者可能会认为它会改变字符串;为了具有描述性,它必须被称为new_with_inserted或类似的奇怪的东西。在日常使用中,“插入”意味着您更改插入的东西的内容(例如,将信封插入邮箱会更改邮箱的内容)。这又提出了一个问题,“为什么我不能更改我的数据存储?”

  4. Ruby 提供了对象的冻结,因此可以安全地传递它们而不会引入细微的错误。好处是 Ruby 像对待任何其他数据结构(数组、散列、类实例)一样对待字符串;他们都可以被冻结。一致性是程序员友好的。不可变字符串使字符串作为一种“特殊”数据结构脱颖而出,但实际上并非如此,如果您将其用作数据存储。

于 2013-05-09T19:29:34.213 回答