+ =运算符似乎修改冻结的字符串

Aks*_*ema 20 ruby

我正在使用红宝石冻结法.考虑到冻结的定义,它会冻结调用它的对象的值.我们无法在其后修改该对象的值.我必须完成相同的任务,我有一个对象,我正在执行以下代码

a = "Test"
a.freeze
a += "this string"
puts a
Run Code Online (Sandbox Code Playgroud)

这给出了如下输出:

Test this string
[Finished in 0.0s]
Run Code Online (Sandbox Code Playgroud)

为什么要修改冻结的字符串?

Nei*_*ter 51

什么都没有修改你的冷冻 String

您正在重新分配a给新String

a += "this string"
Run Code Online (Sandbox Code Playgroud)

这与Ruby内部相同

a = a + "this string"
Run Code Online (Sandbox Code Playgroud)

在Ruby中添加两个String对象时,它将创建一个包含结果的新String(这是+大多数支持它的对象的操作符的正常行为).这使得原始的"Test"和"this string"值保持不变.原始的冻结字符串(包含"测试")将保留在内存中,直到它被垃圾收集.可以收集它,因为您丢失了对它的所有引用.

如果您尝试像这样修改对象:

a << "this string"
Run Code Online (Sandbox Code Playgroud)

那么你应该看到一条错误信息 RuntimeError: can't modify frozen String

基本上,您已将a局部变量与其String指向的对象混淆.可以随时重新分配局部变量,而与Ruby存储的对象无关.您可以通过检查...行a.object_id之前和之后来验证这是您的案例中发生的事情a +=.

  • 另外值得注意的是:`a.object_id`之前和之后完全不同.当东西表现得很奇怪时,这是一个有用的诊断*,就像一个带有克隆元素的数组. (4认同)

Man*_*hah 6

freeze方法可以防止您更改对象,它将对象变成常量

s1 = "its testing"
s1.freeze
puts "Object ID ===", s1.obejct_id
Run Code Online (Sandbox Code Playgroud)

因此,在冻结对象后,尝试修改它会导致类型错误。

s1 << "testing again"
Run Code Online (Sandbox Code Playgroud)

它会给出 RuntimeError: 无法修改冻结的字符串

但,

freeze 对对象引用进行操作,而不是对变量进行操作

s1 += "New Testing"
puts "Object ID ===", s1.obejct_id
Run Code Online (Sandbox Code Playgroud)

将指向评估的新对象并检查其对象 ID。

有关详细信息,请参阅此网站, http://rubylearning.com/satishtalim/mutable_and_immutable_objects.html