方法喜欢attr_accessor
并且has_many
通常被称为“模仿方法”,因为它们看起来有点像 ruby 关键字(模仿它们),但实际上,正如您和其他人正确指出的那样,它们是方法调用。
dd = DooDad.new
dd.foo
输出 nil,从不吐出任何puts
东西
这一切究竟是如何运作的?
当您在类定义中时,所有方法调用和“变量定义”的隐式接收器是self
,在您的情况下是DooDad
.
所以当你写作时
class DooDad
@foo = 1
end
您实际上是在定义一个实例变量 on self
,这恰好是类本身,因为您在该类定义中。(以及在任何其他类、模块或方法定义之外)
attr_accessor
另一方面,在元编程的帮助下,该方法为从 class 实例化的对象的实例变量生成访问器方法DooDad
。
回到你的例子:
class DooDad
attr_accessor :foo
puts "I happened!"
@foo = 7
end
有了上面提到的内容,您现在应该明白您正在处理两个不同的@foo 变量,一个用于 DooDad 类的实例(即DooDad.new
),另一个(您通过编写创建的@foo = 7
)用于 DooDad 类本身!
在类上调用new
方法时,您会创建它的一个实例。
dd = DooDad.new
#=> dd is now an object of class DooDad
dd.foo
#=> You just called the "getter" method for an instance variable foo of object dd, which was never defined before, that's why it's returning nil.
该puts "I happened!"
语句,实际上就像其他两个一样,在加载类时立即进行评估,但在您调用new
它时不会。如果你想要你描述的行为(调用时做事new
),我建议实现一个initialize()
方法 for DooDad
,当你调用时会调用它new
:
class DooDad
attr_accessor :foo
def initialize()
puts "I happened!"
@foo = 7
end
end
dd = DooDad.new
#=> outputs "I happened!" and sets dd.foo = 7
dd.foo
#=> 7
但是为什么@foo = 7
现在设置实例变量dd
and notDooDad
呢?当您使用关键字定义方法时def
,您输入了一个新范围(您通过了范围门)。self
现在不再是类,而是您使用创建的该类的实例,new
就像dd
. 因此,当您在@foo = 7
方法定义内部编写时,您谈论的是类实例的变量DooDad
,而不是类本身。
这篇文章可能太长了,甚至可能无法令人满意,但我希望它有点全面。