Ruby中的冻结变量不起作用

Fil*_*mek 15 ruby arrays variables

我正在学习Ruby,我在使用Object#freeze带变量的方法时发现了有趣的行为.

我冻结变量后(无论是FixnumArray),我仍然可以对其进行修改!这很奇怪,因为就我而言,这不应该发生,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}"
Run Code Online (Sandbox Code Playgroud)

对于数组也是如此:

test = [666]
var = [90]
#ok
var += [5]

puts "var.frozen? #{var.frozen?}"    
var.freeze    
puts "var.frozen? #{var.frozen?}"

var = test
puts "var = #{var}"
Run Code Online (Sandbox Code Playgroud)

但是当我试图在冻结后将某些东西推入阵列时,它会像预期的那样引发恐怖:

test = [666]
var = [90]
#ok
var += [5]

puts "var.frozen? #{var.frozen?}"    
var.freeze    
puts "var.frozen? #{var.frozen?}"

var << test
puts "var = #{var}"
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释这个问题吗?这看起来很奇怪.

编辑我使用的是Windows XP + Ruby 1.9.3-p429

tor*_*o2k 40

您冻结对象而不是变量,即您无法更新冻结对象,但可以将新对象分配给同一变量.考虑一下:

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]
Run Code Online (Sandbox Code Playgroud)

暂时不说:冻结Fixnums 是没用的,因为它们是不可变的对象.


und*_*gor 18

在Ruby中,变量是对象的引用.您冻结对象,而不是变量.

请注意

a = [1, 2]
a.freeze
a += [3]
Run Code Online (Sandbox Code Playgroud)

不是错误,因为+对于数组创建一个新对象.


Den*_*rdy 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
Run Code Online (Sandbox Code Playgroud)

你可以在这里阅读理性:

https://bugs.ruby-lang.org/issues/6037