Ruby代码不在任何方法中

pse*_*ach 9 ruby

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

class DooDad
   attr_accessor :foo
end
Run Code Online (Sandbox Code Playgroud)

要么

class Teacher < ActiveRecord::Base
   has_many :students
end
Run Code Online (Sandbox Code Playgroud)

我认为attr_accessor并且has_many分别使用:foo:students参数调用的方法是正确的吗?如果是这样,何时执行这些类型的语句.我试过这个:

class DooDad
  attr_accessor :foo
  puts "I happened!"
  @foo = 7
end
Run Code Online (Sandbox Code Playgroud)

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

dd = DooDad.new
dd.foo
Run Code Online (Sandbox Code Playgroud)

输出零,从不吐出任何puts东西

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

rat*_*rio 16

类似的方法attr_accessor,并has_many通常被称为"模拟方式",因为它们有点像红宝石关键字(模仿它们),但他们实际上,当你和其他人正确地指出,方法调用.

dd = DooDad.new
dd.foo
Run Code Online (Sandbox Code Playgroud)

输出零,从不吐出任何puts东西

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

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

所以当你写作的时候

class DooDad
  @foo = 1
end
Run Code Online (Sandbox Code Playgroud)

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

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

回到你的例子:

class DooDad
  attr_accessor :foo
  puts "I happened!"
  @foo = 7
end
Run Code Online (Sandbox Code Playgroud)

有了上面提到的东西,你现在应该明白你正在处理两个不同的@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.
Run Code Online (Sandbox Code Playgroud)

puts "I happened!"正如其他两个实际上一样,该语句在加载类时会立即进行评估,但不会在您调用new它时进行评估.如果你想要你描述的行为(在调用时做的事情new),我建议实现一个initialize()方法 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
Run Code Online (Sandbox Code Playgroud)

但是为什么@foo = 7现在设置实例变量dd而不是DooDad?使用关键字定义方法时def,输入新范围(通过范围门).self现在不再是类,而是您创建的类的实例new,就像dd.因此,当您在@foo = 7方法定义内部编写时,您正在讨论类的实例的变量DooDad,而不是类本身.

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


cjh*_*eal 7

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

以下是attr_accessor的文档.