为什么“<<”和“+”与冻结的字符串对象表现不同?

时间:2013-02-16 18:14:45

标签: ruby ruby-1.9.3

irb(main):009:0> a = "good"
=> "good"
irb(main):010:0> a = "good" + "morning"
=> "goodmorning"
irb(main):011:0> a = "good"
=> "good"
irb(main):012:0> a << " morning"
=> "good morning"

到目前为止, concatenation 运算符都正常运行。

irb(main):013:0> a = "good"
=> "good"

irb(main):014:0> a.freeze
=> "good"

irb(main):015:0> a.frozen?
=> true

irb(main):016:0> a << " welcome"
RuntimeError: can't modify frozen String
    from (irb):16
    from /usr/bin/irb:12:in `<main>'


irb(main):017:0> a = a +  " welcome"
=> "good welcome"

但是使用 frozen 字符串可以清楚地看到IRB <<+表现不同的{{1}}差异。谁能告诉我这个的原因?

3 个答案:

答案 0 :(得分:5)

他们正在完全他们应该做的事情。 << 修改了调用它的字符串,而+更接近str.dup << arg。此行为是已定义的文档标准。

答案 1 :(得分:1)

@Linuxios的答案是完美的。

但仍然在这里,我试图以更透明的方式显示修改:

@ubuntu:~$ irb --simple-prompt
>> a = "good"
=> "good"

>> a.freeze
=> "good"

>> a.frozen?
=> true

>> a.object_id
=> 10557720 # holds the reference to the "good" string object.

>> a = a + " morning"
=> "good morning"

>> a.object_id
=> 10415700 # holds the reference to the new string object "good morning". 

>> a.frozen?
=> false

>> ObjectSpace._id2ref(10415700)
=> "good morning"
>> ObjectSpace._id2ref(10557720)
=> "good"
>> ObjectSpace._id2ref(10557720).frozen?
=> true

我们可以得出结论 - 是的,字符串“good”仍然被冻结。只有发生的事情是a引用新对象“早上好”。只有a的参考分配已更改。

答案 2 :(得分:0)

<<+对所有字符串对象的行为不同,而不仅仅是冻结对象。一个(<<)修改一个字符串,另一个(+)返回一个新字符串而不修改原始字符串:

使用<<

string1 = "good"
#=> "good"
string2 = string1
#=> "good"
string1 << " morning"
#=> "good morning"
string1
#=> "good morning"
string2
#=> "good morning"

使用+

string1 = "good"
#=> "good"
string2 = string1
#=> "good"
string1 = string1 + " morning"
#=> "good morning"
string1
#=> "good morning"
string2
#=> "good"

Object#freeze专门用于禁止我在上面用<<演示的行为(它可以防止对象被修改),因此在冻结的字符串上调用<<会导致错误