4

在下面的两个示例中,我做同样的事情,创建一个常量 String 并使用 concat 方法对其进行修改。因为它是一个常量,所以我期望一个编译器警告,但是当我使用赋值运算符时,在第二个示例中只收到一个警告。为什么是这样?

X = "hello"
X.concat(" world")
puts X # no warning

X = "hello"
X = X.concat(" world")
puts X # warning: already initialized

由于 concat 方法修改了字符串,这通常是我会做的,因为不需要使用赋值运算符。那么,为什么赋值运算符的存在会导致编译器将这两个操作识别为不同的呢?

4

4 回答 4

7

在 Ruby 中,变量本质上是指向包含对象的内存中某个位置的指针,而不是对象本身。在第二个示例中,您在X第一行(X = "hello"

常量的不变性并不意味着你不能改变对象——它只是意味着你不能改变常量来指向另一个对象。

于 2009-03-21T22:18:34.370 回答
6

这是因为您正在重新定义一个新的 X。当您重新定义一个常量时,它会给您“已经初始化”错误。第一个示例没有给出此错误,因为您不是在重新定义 X,而是在修改它。

于 2009-03-21T22:19:46.113 回答
4

如果你想让你的字符串“真实”不变,请尝试“冻结”:

X = "foo".freeze        # => "foo" 
X.concat("bar")

TypeError: can't modify frozen string
    from (irb):2:in `concat'
    from (irb):2

我真的鼓励您阅读The Ruby Programming Language

于 2009-03-21T22:52:37.173 回答
0

这是因为常量X存储了对String对象的引用。在您的第一个示例中,您正在修改String对象的内部状态,而不是常量存储的引用。在第二个示例中,您将常量存储的引用更改为String从方法返回的新对象concat

PickAxe 书在这里解释了这一点。

于 2009-03-21T22:26:24.460 回答