【发布时间】:2016-08-27 06:13:27
【问题描述】:
我看到字符串的object_id 总是不同的,而符号的object_id 是相同的(如果值相等)。据我了解,符号和字符串之间的区别在于不变性和性能。我们不能在变量中存储一个字符串并冻结它吗?
【问题讨论】:
我看到字符串的object_id 总是不同的,而符号的object_id 是相同的(如果值相等)。据我了解,符号和字符串之间的区别在于不变性和性能。我们不能在变量中存储一个字符串并冻结它吗?
【问题讨论】:
freeze 防止修改实际对象,但是变量是对对象的引用,因此您仍然可以更改引用。下面的例子是完全有效的。
a = "foo"
a.freeze
a = "boo"
在这个a的末尾等于“boo”。
在 Ruby 2.1 及更早的版本中,为符号分配了可用的object_id,并且任何时候使用相同的符号标识符,都将始终使用相同的 object_id;这永远不会被垃圾收集。这是不可变的,但效率更高(内存开销更少)。
在 Ruby 2.2 及更高版本中,行为基本相同,除了符号可以被垃圾收集。进行此更改的原因是为了防止符号 DoS 攻击。
【讨论】:
[...] 我们不能在变量中存储一个字符串并冻结它吗?
几乎,最新版本的 Ruby 可以优化冻结字符串:
'foo'.freeze.object_id #=> 70313275108080
'foo'.freeze.object_id #=> 70313275108080
但是这种优化是有限的。它适用于字符串 literals(如上所示),但如果字符串稍后被冻结则不起作用:
a = 'foo'
a.freeze
a.object_id #=> 70313275335500
b = 'foo'
b.freeze
b.object_id #=> 70313275274260
除非您启用frozen_string_literal 功能:
# frozen_string_literal: true
puts 'foo'.object_id
puts 'foo'.object_id
输出:
$ ruby test.rb
70185151269500
70185151269500
或者,从命令行:
$ ruby --enable-frozen-string-literal -e "puts 'foo'.object_id, 'foo'.object_id"
70102955495340
70102955495340
【讨论】: