1

考虑到这个简单的代码:

class Yeah
  attr_reader :foo
  attr_reader :fool
  attr_reader :feel
  def initialize(foo: "test", fool: {}, feel: [])
    @foo = foo
    @fool = fool
  end
end

test = Yeah::new
pp test
test.fool[:one] = 10
pp test

输出 :

#<Yeah:0x000008019a84a0 @foo="test", @fool={}>
#<Yeah:0x000008019a84a0 @foo="test", @fool={:one=>10}>

我的问题是,有一种“简单”、“干净”的方式,可以读取真正的只读数组、哈希属性的访问器,或者我需要继承数组或哈希,并且有很多难以编写的锁定,(undef,别名)或使用代理、委托或其他类似的模式?

4

3 回答 3

2

您可以想到以下内容:

class Yeah
  def self.reader_meth
    %i(foo fool feel).each do |m|
      define_method(m){instance_variable_get("@#{m}").dup.freeze}
    end
  end
  def initialize(foo: "test", fool: {}, feel: [])
    @foo = foo
    @fool = fool
    @feel =feel
  end
  reader_meth
end

test = Yeah.new
test # => #<Yeah:0x8975498 @foo="test", @fool={}, @feel=[]>
test.fool[:one] = 10 # can't modify frozen Hash (RuntimeError)
test # => #<Yeah:0x8975498 @foo="test", @fool={}, @feel=[]>
于 2013-10-18T09:41:51.500 回答
1

因为我想概括这个解决方案并防止“邪恶”评估:

我终于,从 Arup 解决方案到了这个:

class Module
  def attr_readonly *syms
    syms.each do |method|
      define_method(method){
        return self.instance_variable_get("@#{method.to_s}").dup.freeze 
      }
    end
  end
end

class Yeah

  attr_reader :foo
  attr_readonly :fool
  attr_reader :feel
  def initialize(foo: "test", fool: {}, feel: [])
    @foo = foo
    @fool = fool
    @feel = feel
  end

end
于 2013-10-18T11:07:05.320 回答
0

怎么样Object#freeze

class Yeah
  def fool
    @fool.freeze
  end 
  def initialize(fool={})
    @fool = fool
  end
end
于 2013-10-18T09:29:00.970 回答