如何解冻Ruby中的对象?

前端之家收集整理的这篇文章主要介绍了如何解冻Ruby中的对象?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Ruby中有 Object#freeze,可以防止对对象的进一步修改
class Kingdom
  attr_accessor :weather_conditions
end

arendelle = Kingdom.new
arendelle.frozen? # => false
arendelle.weather_conditions = 'in 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

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

解决方法

是和否没有任何使用标准API的直接方式.但是,有一些了解什么#freeze?是的,你可以解决它.注意:这里的一切都是MRI当前版本的实现细节,可能会有所变化.

CRuby中的对象存储在struct RVALUE中.
方便的是,结构中的第一件事是VALUE标志.
所有对象#freeze都设置了一个标志,称为FL_FREEZE,实际上是equal to RUBY_FL_FREEZE.RUBY_FL_FREEZE基本上是标志中的11th bit.
所有你要解冻的对象都要取消设置第11位.

为此,您可以使用Fiddle,它是标准库的一部分,可让您修改C级语言:

require 'fiddle'

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

immediate value objects in Ruby存储在address =他们的object_id * 2上.请注意,重要的是进行区分,以便您知道这不会让您解冻Fixnums.

由于我们要改变第11位,所以我们必须使用第二个字节的第3位.因此,我们使用[1]访问第二个字节.

〜(1 <3)移动3个位置,然后使结果反转.这样,掩码中零位的唯一位将是第三个,所有其他将是一个. 最后,我们只用位和(& =)应用掩码.

foo = 'A frozen string'.freeze
foo.frozen? # => true
foo.unfreeze
foo.frozen? # => false
foo[/ (?=frozen)/] = 'n un'
foo # => 'An unfrozen string'

猜你在找的Ruby相关文章