Ruby代码不在任何方法中

时间:2012-08-21 21:18:41

标签: 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,永不吐出任何puts内容

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

3 个答案:

答案 0 :(得分:16)

attr_accessorhas_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_manyattr_accessor等方法实际上是模块或类的方法。你对它们是正常的方法是绝对正确的,用其他任何参数调用参数。当一个方法直接在类中调用时(在方法定义之外),它就在类本身上被调用。

以下是attr_accessor的文档。

答案 2 :(得分:-2)

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

class Foo
  attr_accessor :bar
end

它实际上是......的简写。

class Foo
  def bar
    @bar
  end

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