Ruby代码不在任何方法中
一般Ruby问题:在Ruby中,我经常看到类中的代码,但不是方法的一部分。 例如:
class DooDad attr_accessor :foo end
要么
class Teacher < ActiveRecord::Base has_many :students end
我认为attr_accessor
和has_many
是分别用:foo
或:students
参数调用的方法,是吗? 如果是这样,何时执行这些类型的语句。 我试过这个:
class DooDad attr_accessor :foo puts "I happened!" @foo = 7 end
它似乎没有运行这些new
方法的一部分:
dd = DooDad.new dd.foo
输出nil,永远不会吐出任何东西
这一切究竟是如何运作的?
像attr_accessor
和has_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_many
和attr_accessor
这样的方法实际上是Module或Class上的方法。 你对它们是正常的方法是完全正确的,用其他任何参数调用参数。 当一个方法直接在类中调用(在方法定义之外)时,它就在类本身上被调用。
以下是attr_accessor的文档。
它们是语言中内置的语法糖,因此它与您的测试不同。 当你写(例如)
class Foo attr_accessor :bar end
它实际上是…的简写
class Foo def bar @bar end def bar=(value) @bar = value end end