我正在学习Ruby,我在使用Object#freeze
方法和变量时发现了有趣的行为。
冻结变量(Fixnum
或Array
)后,我仍然可以修改它!这很奇怪,因为就我而言,这不应该发生,应该提出TypeError
。
这是我的代码:
test = 666
var = 90
#ok
var += 5
puts "var.frozen? #{var.frozen?}"
var.freeze
puts "var.frozen? #{var.frozen?}"
var = test
puts "var = #{var}"
同样适用于数组:
test = [666]
var = [90]
#ok
var += [5]
puts "var.frozen? #{var.frozen?}"
var.freeze
puts "var.frozen? #{var.frozen?}"
var = test
puts "var = #{var}"
但是当我试图在冻结后将某些东西推入阵列时,它会像预期的那样引发恐怖:
test = [666]
var = [90]
#ok
var += [5]
puts "var.frozen? #{var.frozen?}"
var.freeze
puts "var.frozen? #{var.frozen?}"
var << test
puts "var = #{var}"
有人可以向我解释这个问题吗?这看起来很奇怪。
编辑我使用的是Windows XP + Ruby 1.9.3-p429
答案 0 :(得分:38)
您冻结对象而不是变量,即您无法更新冻结对象,但可以将新对象分配给同一变量。考虑一下:
a = [1,2,3]
a.freeze
a << 4
# RuntimeError: can't modify frozen Array
# `b` and `a` references the same frozen object
b = a
b << 4
# RuntimeError: can't modify frozen Array
# You can replace the object referenced by `a` with an unfrozen one
a = [4, 5, 6]
a << 7
# => [4, 5, 6, 7]
顺便说一下:冻结Fixnum
是没用的,因为它们是不可变对象。
答案 1 :(得分:18)
在Ruby中,变量是对象的引用。你冻结了对象,而不是变量。
请注意
a = [1, 2]
a.freeze
a += [3]
不是错误,因为数组的+
会创建一个新对象。
答案 2 :(得分:13)
正如其他两个答案中所提到的,你冻结对象而不是变量。
我想在子对象上添加一个注释,当父对象被冻结时,它们不会被冻结。如果你在暴露对象的内部结构时不注意你正在做的事情,这会让你很难受:
class A
attr_accessor :var
end
a = A.new
a.var = []
a.freeze
a.var = [] # this fails as expected
a.var << :a # this works, raises no errors, and no warnings
你可以在这里阅读理性: