Sql 为什么我能够像调用实例方法一样调用类方法呢?

Sql 为什么我能够像调用实例方法一样调用类方法呢?,sql,ruby,metaprogramming,Sql,Ruby,Metaprogramming,我在看这个例子: class SQLObject def self.columns return @columns if @columns columns = DBConnection.execute2(<<-SQL).first SELECT "#{table_name}".* FROM "#{table_name}" LIMIT 0 SQL columns.ma

我在看这个例子:

class SQLObject
  def self.columns
    return @columns if @columns
    columns = DBConnection.execute2(<<-SQL).first
      SELECT
        "#{table_name}".*
      FROM
        "#{table_name}"
      LIMIT
        0
    SQL
    columns.map!(&:to_sym)
    @columns = columns
  end

  def self.table_name
    @table_name ||= self.name.underscore.pluralize
  end

  def insert
    column_symbols = self.class.columns.drop(1)
    column_names = column_symbols.map(&:to_s).join(", ")
    question_marks = (['?'] * column_symbols.count).join(", ")
    DBConnection.execute(<<-SQL, *attribute_values)
      INSERT INTO
        #{self.class.table_name} (#{column_names})
      VALUES
        (#{question_marks})
    SQL
    self.id = DBConnection.last_insert_row_id
  end
end
类SQLObject def self.columns 如果@columns,则返回@columns
columns=DBConnection.execute2(当在抽象类中时,
self
指的是正确的类,而不是对象。这就是为什么您可以访问该方法,而无需显式告诉
self
简短回答:
self
是Ruby中的隐式接收器。如果您省略它,消息将发送到
self
。换句话说,它是never必须在消息发送中说
self.foo
,因为
foo
总是隐式地与
self.foo
相同

详细回答:Ruby中没有“类方法”这样的东西。你所说的“类方法”实际上只是在一个对象上定义的一个单例方法,而这个对象恰好是类的一个实例

实际上,Ruby中也没有单例方法。单例方法实际上只是一个在对象的单例类上定义的常规旧实例方法

[注意:这并不是说你不应该使用这些术语。说“类方法”显然比“类的对象的单例类的实例方法<代码>类”更简单,传达的意图也更好。”。此外,请注意,有些方法,例如。这些术语显然存在于Ruby社区中,但重要的是要理解这些概念在Ruby语言中并不存在。它们是一种交流工具,而不是实际的Ruby概念。]

singleton类是一个与单个对象关联的类。每个对象只有一个singleton类,并且该对象是其singleton类的唯一实例(“singleton instance”,因此得名)

事实上,一个对象的继承层次结构总是从它的单例类开始,也就是说,一个对象的类指针总是指向它的单例类,而单例类的超类指针则指向创建这个对象的类计算继承链时“跳过”单例类。但是,在方法查找过程中始终使用该类

事实上,方法查找实际上非常简单(唯一的例外是,在本文的解释中我将忽略它):

  • 取消引用接收方的类指针
  • 如果该类的方法表中有一个消息名为的方法,则调用它。停止
  • 如果不是,则取消引用类的超类指针
  • 后藤2号
  • 如果到达的类没有超类,则使用消息重新启动算法,除非消息名称已
    method\u missing
    ,在这种情况下,引发错误
  • 因此,这一切归结为两个问题:

    • 定义方法时,您在哪个类(或模块)中定义它
    • 发送消息时,您将消息发送到哪个对象
    使用
    def foo.bar
    定义方法时,Ruby将首先计算表达式
    foo
    ,然后在结果对象的单例类(被定义对象)上定义方法
    bar
    。如果您不提供
    foo
    ,即您只说
    def bar
    ,则
    bar
    是在上定义的,这是一个有点棘手的概念。通常,它是最接近词汇的封闭模块定义。如果没有封闭模块定义,即您处于顶层,则默认定义对象为,方法为vi不可能

    当您使用
    foo.bar
    发送消息时,Ruby将首先计算表达式
    foo
    ,然后将消息
    bar
    发送给结果对象(接收者)。如果您不提供
    foo
    ,即如果您只说
    bar
    ,那么默认接收者是
    self

    这就引出了下一个问题:

    • 什么是自我
    在方法定义体中,
    self
    是导致调用此方法的消息send的接收者。因此,如果您发送消息
    foo.bar
    ,则在方法
    bar
    的定义中对
    self
    的任何引用都将在方法的这一次执行期间计算为
    foo

    在模块或类定义主体中,
    self
    是类或方法本身。(这就是为什么在模块或类定义主体中使用
    def self.bar
    定义单例类的单例方法实例方法。)

    在一个块或lambda文本中,
    self
    在词汇上被捕获,也就是说,
    self
    在写入块或lambda文本的点上是什么。然而,有两种方法可以改变
    self
    的计算方式,最显著的是,,,…系列方法

    如果您在代码中的任何时候都知道这三个问题的答案(我在哪里定义一个方法,方法调用的接收者是什么,self是什么),那么您基本上理解了Ruby最重要的部分

    所以,把这一切放在一起:

    在使用
    def self.columns
    定义方法时,我们处于类定义主体中,因此
    self
    引用类对象本身(
    SQLObject

    语法
    def foo.bar
    foo
    的单例类上定义了一个方法
    bar
    。在这种情况下,您在
    SQLObject
    的单例类上定义了方法
    columns
    。这意味着对象
    SQLObject
    是宇宙中唯一会响应消息
    c>的对象列

    这两者也适用于
    self.table\u name
    的定义

    大都会公园内