其实severin 有一个更好的主意,只是因为method_missing 的使用是一种不好的做法,并非一直如此,但大部分时候都是这样。
severin 提供的代码存在一个问题:它返回已传递给初始化程序的值,因此您无法更改它。我建议你采取一些不同的方法:
class User < Hash
def initialize(attrs)
attrs.each do |k, v|
self[k] = v
end
end
def []=(k, v)
unless respond_to?(k)
self.class.send :define_method, k do
self[k]
end
end
super
end
end
让我们检查一下:
u = User.new(:name => 'John')
p u.name
u[:name] = 'Maria'
p u.name
你也可以用 Struct 做到这一点:
attrs = {:name => 'John', :age => 22, :position => 'developer'}
keys = attrs.keys
user = Struct.new(*keys).new(*keys.map { |k| attrs[k] })
让我们测试一下:
p user
p user.name
user[:name] = 'Maria'
p user.name
user.name = 'Vlad'
p user[:name]
甚至是OpenStruct,但要注意如果它已经在实例方法中,它不会创建方法,你可以使用OpenStruct.instance_methods来查找它(因为使用了类型,我现在使用第二种方法):
attrs = {:name => 'John', :age => 22, :position => 'developer'}
user = OpenStruct.new(attrs)
是的,很简单:
user.name
user[:name] # will give you an error, because OpenStruct isn't a Enumerable or Hash