深度冻结变量 Deep Freeze

Ruby自带的freeze无法深度冻结,如:

$ irb
2.4.4 :001 > h={a: [1,2], b: { c: [2,3]}, c: 'hello'}.freeze
 => {:a=>[1, 2], :b=>{:c=>[2, 3]}, :c=>"hello"}
2.4.4 :002 > h[:c] << ' there'
 => "hello there"
2.4.4 :003 > h
 => {:a=>[1, 2], :b=>{:c=>[2, 3]}, :c=>"hello there"}

通过下面扩展,可以实现深度冻结:

# Recursively freeze self if it's Enumerable
# Supports all Ruby versions 1.8.* to 2.2.*+
module Kernel
  alias deep_freeze freeze
  alias deep_frozen? frozen?
end

module Enumerable
  def deep_freeze
    if !@deep_frozen
      each(&:deep_freeze)
      @deep_frozen = true
    end
    freeze
  end

  def deep_frozen?
    !!@deep_frozen
  end
end
2.4.4 :021 > h={a: [1,2], b: { c: [2,3]}, c: 'hello'}.deep_freeze
 => {:a=>[1, 2], :b=>{:c=>[2, 3]}, :c=>"hello"}
2.4.4 :022 > h[:c] << ' there'
RuntimeError: can't modify frozen String
	from (irb):22
	from /Users/xiaohui/.rvm/rubies/ruby-2.4.4/bin/irb:11:in `<main>'

Last updated