Ruby如何使用符号来引用变量名?

时间:2012-10-06 15:23:56

标签: ruby metaprogramming

当我们在以下代码中为name定义getter和setter方法时:

class Animal
    attr_accessor :name
    def initialize(name)
        @name = name
    end
end

内部发生了什么? Ruby如何获取符号并将其与变量匹配?

2 个答案:

答案 0 :(得分:6)

它使用instance_variable_getinstance_variable_set

更新:正如安德鲁马歇尔所指出的那样,并非如此。大多数ruby核心方法都是用C定义的,但结果基本相同。

可以按如下方式定义attr_accessor和朋友:

def self.attr_accessor(*names)
  names.each do |name|
    define_method(name) do
      instance_variable_get("@#{name}")
    end

    define_method("#{name}=") do |new_value|
      instance_variable_set("@#{name}", new_value)
    end
  end
end

请注意,我在这里也使用define_method来定义访问器方法。

我建议您查看一些关于ruby元编程的介绍性文本,例如"Don’t Know Metaprogramming In Ruby?"

答案 1 :(得分:2)

它与变量不匹配,attr_accessor基本上就是这个(它实际上是用C编写的,但我在这里写的大致是Ruby翻译):

def attr_accessor(var_name)
  ivar_name = :"@#{var_name}"
  define_method(var_name) do
    instance_variable_get ivar_name
  end
  define_method("#{var_name}=") do |value|
    instance_variable_set ivar_name, value
  end
end

如您所见,它只是使用传递的符号来创建两个方法。它没有对符号做任何花哨的事情,而且大部分只是通过它。另请注意,默认情况下所有实例变量都“存在”并设置为nil,因此永远不会爆炸。