这个值变量来自哪里?

时间:2019-12-05 02:57:39

标签: ruby metaprogramming attr-accessor

我正在阅读一个示例,该示例如何使用元编程来创建属性访问器,并且我对该值变量的来源有些困惑:

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} =”)的值是一个值数组,对吗?

3 个答案:

答案 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)

不应否认所引用的代码存在某些弱点。

  1. 无需将Object#instance_variable_getObject#instance_variable_set的第一个参数转换为符号。

  2. (挑剔),self.不必位于instance_variable_getinstance_variable_set之前,因为在没有任何调用的情况下,self是隐式接收者显式接收者。

  3. (主要),该方法不必要地复杂,因为使用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"