【发布时间】:2012-10-06 15:23:55
【问题描述】:
当我们在下面的代码中为name定义getter和setter方法时:
class Animal
attr_accessor :name
def initialize(name)
@name = name
end
end
内部发生了什么? Ruby 如何获取符号并将其与变量匹配?
【问题讨论】:
标签: ruby metaprogramming
当我们在下面的代码中为name定义getter和setter方法时:
class Animal
attr_accessor :name
def initialize(name)
@name = name
end
end
内部发生了什么? Ruby 如何获取符号并将其与变量匹配?
【问题讨论】:
标签: ruby metaprogramming
为此它使用instance_variable_get 和instance_variable_set。
更新:正如 Andrew Marshall 所说,不完全是。大多数 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?"。
【讨论】:
它与变量不匹配,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,所以这永远不会爆炸。
【讨论】: