一般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,永不吐出任何puts
内容
这一切究竟是如何运作的?
答案 0 :(得分:16)
像attr_accessor
和has_many
这样的方法通常被称为“模仿方法”,因为它们看起来像红宝石关键字(模仿它们)但实际上它们正如您和其他人正确指出的那样,方法调用。
dd = DooDad.new
dd.foo
输出nil,永不吐出任何
puts
内容这一切究竟是如何运作的?
当你在类定义中时,所有方法调用的隐式接收者和“变量定义”都是self
,在你的情况下是DooDad
。
所以当你写作时
class DooDad
@foo = 1
end
你实际上是在self
上定义一个实例变量,恰好是类本身,因为你在这个类定义中。 (以及任何其他类,模块或方法定义之外)
另一方面,方法attr_accessor
在元编程的帮助下生成了访问器方法,用于从类DooDad
实例化的对象的实例变量。< / p>
回到你的例子:
class DooDad
attr_accessor :foo
puts "I happened!"
@foo = 7
end
使用上面提到的东西,你现在应该明白你正在处理两个不同的@foo变量,一个用于类DooDad的实例(即DooDad.new
),另一个用你写的{{ {1}})类DooDad本身!
在类上调用@foo = 7
方法时,可以创建它的实例。
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()
方法,当你调用DooDad
时会调用它:< / p>
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
的实例的变量,而不是类本身。
这篇文章可能太长了,甚至可能不满足作为答案,但我希望它有点全面。
答案 1 :(得分:7)
has_many
和attr_accessor
等方法实际上是模块或类的方法。你对它们是正常的方法是绝对正确的,用其他任何参数调用参数。当一个方法直接在类中调用时(在方法定义之外),它就在类本身上被调用。
以下是attr_accessor的文档。
答案 2 :(得分:-2)
它们是语言中内置的语法糖,因此它与您的测试不同。当你写(例如)
class Foo
attr_accessor :bar
end
它实际上是......的简写。
class Foo
def bar
@bar
end
def bar=(value)
@bar = value
end
end