方法喜欢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现在设置实例变量ddand notDooDad呢?当您使用关键字定义方法时def,您输入了一个新范围(您通过了范围门)。self现在不再是类,而是您使用创建的该类的实例,new就像dd. 因此,当您在@foo = 7方法定义内部编写时,您谈论的是类实例的变量DooDad,而不是类本身。
这篇文章可能太长了,甚至可能无法令人满意,但我希望它有点全面。