如何在Ruby中解冻对象?
在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
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我将为该对象执行方法体。AkaFiddle::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']