我正在阅读一个示例,该示例如何使用元编程来创建属性访问器,并且我对该值变量的来源有些困惑:
class AttrAccessorObject
def self.my_attr_accessor(*names)
names.each do | name |
define_method(name) {
self.instance_variable_get("@#{name}".to_sym)
}
define_method("#{name}=") do | value |
self.instance_variable_set("@#{name}".to_sym, value)
end
end
end
end
我知道instance_variable_set方法既需要实例变量又需要值来设置实例变量的新值,但是该值变量在代码中是哪里来的呢?另外,由于它使用“ do / end”循环来使用值,所以我假设“ define_method(“#{name} =”)的值是一个值数组,对吗?
答案 0 :(得分:1)
如果您想到“普通”方法的定义是什么?
def some_name=(value)
@some_name = value
end
|value|
部分与(value)
相同-它声明了您所定义的方法所接受的参数。因此,如果我想制作一个采用3个参数的方法:
define_method(:some_method) do |arg1, arg2, arg2|
[arg1, arg2, arg3]
end
此外,由于它使用“ do / end”循环来使用值,因此我假设“ define_method(“#{name} =”)的值计算为值的数组,对吗? >
不,块不仅仅与数组一起使用。可以将一个块当作一个匿名函数,用作另一个函数的参数。您调用的函数(例如each
)可以在内部调用匿名函数0、1或任意多次。对于each
,它将调用N次(每个数组元素一次):
def my_each(array, &blk)
for elem in array do
blk.call(elem)
end
end
但是对于tap
,它只调用一次:
def my_tap(obj, &blk)
blk.call(obj)
obj
end
答案 1 :(得分:1)
value
是您正在定义的方法签名的一部分。
define_method
可以解释为在代码块中添加“标签”,并将其引用保存在类中以供以后使用。
define_method("print_two_values") do | value1, value2 |
puts "first: #{value1}, second: #{value2}"
end
可以改写为
def print_two_values(value1, value2)
puts "first: #{value1}, second: #{value2}"
end
答案 2 :(得分:0)
不应否认所引用的代码存在某些弱点。
无需将Object#instance_variable_get和Object#instance_variable_set的第一个参数转换为符号。
(挑剔),self.
不必位于instance_variable_get
和instance_variable_set
之前,因为在没有任何调用的情况下,self
是隐式接收者显式接收者。
(主要),该方法不必要地复杂,因为使用Ruby的方法Module#attr_accessor更加容易,该方法专门用于创建getter和setter方法:
class AttrAccessorObject
def self.my_attr_accessor(*names)
attr_accessor(*names)
end
end
AttrAccessorObject.my_attr_accessor "pig", "owl"
#=> ["pig", "owl"]
AttrAccessorObject.instance_methods(false)
#=> [:pig, :pig=, :owl, :owl=]
inst = AttrAccessorObject.new
#=> #<AttrAccessorObject:0x00005661152d6ed8>
inst.owl = 'hoot'
#=> "hoot"
inst.owl
#=> "hoot"