如何在Ruby中解冻对象?

如何在Ruby中解冻对象?,ruby,Ruby,在Ruby中,存在阻止进一步修改对象的: class Kingdom attr_accessor :weather_conditions end arendelle = Kingdom.new arendelle.frozen? # => false arendelle.weather_conditions = 'in deep, deep, deep, deep snow' arendelle.freeze arendelle.frozen? # => true arende

在Ruby中,存在阻止进一步修改对象的:

class Kingdom
  attr_accessor :weather_conditions
end

arendelle = Kingdom.new
arendelle.frozen? # => false
arendelle.weather_conditions = 'in deep, deep, deep, deep snow'
arendelle.freeze
arendelle.frozen? # => true
arendelle.weather_conditions = 'sun is shining'
  # !> RuntimeError: can't modify frozen Kingdom

script = 'Do you want to build a snowman?'.freeze
script[/snowman/] = 'castle of ice'
  # !> RuntimeError: can't modify frozen String

但是,没有对象#解冻。有没有办法解冻冰冻的王国?

更新从Ruby 2.7开始,这不再有效


是和否。使用标准API没有任何直接的方法。但是,只要对
#freeze?
的功能有所了解,就可以解决这个问题。注意:这里的所有内容都是MRI当前版本的实施细节,可能会发生更改


CRuby中的对象存储在结构中。
方便地说,结构中的第一件事是
值标志
所有的
Object#freeze
都设置了一个标志,称为
FL#u freeze
,实际上是
RUBY\u FL\u FREEZE
基本上是标志中的首选项。
解冻对象所需做的就是取消第11位的冻结

要做到这一点,您可以使用,它是标准库的一部分,可以让您在C级别上修补语言:

require 'fiddle'

class Object
  def unfreeze
    Fiddle::Pointer.new(object_id * 2)[1] &= ~(1 << 3)
  end
end
不,根据:

无法解冻冻结的对象

冻结状态存储在对象中。调用
freeze
设置冻结状态,从而防止进一步修改。这包括对对象冻结状态的修改

关于您的示例,您可以指定一个新字符串:

script = 'Do you want to build a snowman?'
script.freeze

script = script.dup if script.frozen?
script[/snowman/] = 'castle of ice'
script #=> "Do you want to build a castle of ice?"

引入了Ruby 2.3,因此您可以编写
+str
,而不是
str.dup(如果str.freezed?

),如上所述,将变量复制回自身也可以有效地解冻变量

如前所述,这可以使用.dup方法完成:

var1=var1.dup

这也可以通过以下方式实现:

var1=Marshal.load(Marshal.dump(var1))

我一直在使用
Marshal.load(Marshal.dump(

我没有使用过
.dup
,只是通过这篇文章了解到了这一点

我不知道
Marshal.load(Marshal.dump(


如果他们做同样的事情,或者
.dup
功能更强大,那么从风格上来说,我更喜欢
.dup
.dup
说明了要做什么——复制这个东西,但它没有说明如何做,而
Marshal.load(Marshal.dump(
不仅过于冗长,而且说明了如何进行复制——如果how部分与我无关,我不喜欢指定how部分。我想复制变量的值,我不在乎如何复制。

搞乱Ruby的内部结构是有风险的。你应该在回答中说明这一点。@Stefan,我在ope中提到过我认为这是不言而喻的。“NDN你是对的,我完全忽略了。但是一个符号有直接的价值吗?然而,可能有一种情况,一个对象的冻结状态被认为是理所当然的,改变它会导致意想不到的行为。”斯特凡,根据文献,即时价值是我们。为零、真、假、固定值、符号和一些Floats@Jonathan我将为该对象执行方法体。Aka
Fiddle::Pointer.new(stuff_to_unfreeze.object_id*2)[1]&=~(1)我特别喜欢你提到字符串#+@部分,因为这是一个相当新的部分,提到它似乎是一个很好的用途。我记得我注意到nobu当时通过changelog在那里做了一些更改,我不知道+str。Ruby 3.0中的
Ractor
的不可自由化特别重要dify对象,它修改它的副本。因为你不应该在Ruby中“解冻”冻结的对象,所以这个功能的目的基本上是让你的对象保持不变。即使是Rubocop,很久以前也引入了一个规则,其中每个.rb都应该有“神奇的Ruby注释”常量应该始终处于冻结状态。Ruby 2.6默认情况下已经提供了此功能。我相信这是正确的答案。复制变量并根据需要修改它。
frozen_object = %w[hello world].freeze
frozen_object.concat(['and universe']) # FrozenError (can't modify frozen Array)
frozen_object.dup.concat(['and universe']) # ['hello', 'world', 'and universe']
frozen_object = %w[hello world].freeze
frozen_object.concat(['and universe']) # FrozenError (can't modify frozen Array)
frozen_object.dup.concat(['and universe']) # ['hello', 'world', 'and universe']