Ruby代码不在任何方法中

一般Ruby问题:在Ruby中,我经常看到类中的代码,但不是方法的一部分。 例如:

class DooDad attr_accessor :foo end 

要么

 class Teacher < ActiveRecord::Base has_many :students end 

我认为attr_accessorhas_many是分别用:foo:students参数调用的方法,是吗? 如果是这样,何时执行这些类型的语句。 我试过这个:

 class DooDad attr_accessor :foo puts "I happened!" @foo = 7 end 

它似乎没有运行这些new方法的一部分:

 dd = DooDad.new dd.foo 

输出nil,永远不会吐出任何东西

这一切究竟是如何运作的?

attr_accessorhas_many这样的方法通常被称为“模仿方法”,因为它们看起来像ruby关键字(模仿它们)但事实上,正如你和其他人正确指出的那样,方法调用。

 dd = DooDad.new dd.foo 

输出nil,永远不会吐出任何东西

这一切究竟是如何运作的?

当你在类定义中时,所有方法调用的隐式接收器和“变量定义”都是self ,在你的情况下是DooDad

所以当你写作的时候

 class DooDad @foo = 1 end 

你实际上是在self上定义一个实例变量,恰好是类本身,因为你在这个类定义中。 (以及任何其他类,模块或方法定义之外)

另一方面, attr_accessor方法在元编程的帮助下,生成了从类DooDad实例化的对象的实例变量的访问器方法。

回到你的例子:

 class DooDad attr_accessor :foo puts "I happened!" @foo = 7 end 

有了上面提到的东西,你现在应该明白你正在处理两个不同的@foo变量,一个用于类DooDad(即DooDad.new )的实例,另一个用于(通过编写@foo = 7创建的@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时做的事情),我建议为DooDad实现一个initialize()方法,当你调用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的实例变量而不是DooDad ? 使用关键字def定义方法时,输入新范围(传递范围门)。 self现在不再是类了,而是用new创建的那个类的实例,就像dd一样。 因此,当您在方法定义中编写@foo = 7 ,您正在讨论类DooDad的实例的变量,而不是类本身。

这篇文章可能太长了,甚至可能不满足作为答案,但我希望它有点全面。

has_manyattr_accessor这样的方法实际上是Module或Class上的方法。 你对它们是正常的方法是完全正确的,用其他任何参数调用参数。 当一个方法直接在类中调用(在方法定义之外)时,它就在类本身上被调用。

以下是attr_accessor的文档。

它们是语言中内置的语法糖,因此它与您的测试不同。 当你写(例如)

 class Foo attr_accessor :bar end 

它实际上是…的简写

 class Foo def bar @bar end def bar=(value) @bar = value end end