4

好的,所以我正在尝试在 Ruby 中进行一些元编程,但我有点困惑。根据我读过的几篇文章(如这篇文章),为了向 Ruby 类动态添加类方法,您必须使用该类的单例类:

class Klass
end

class << Klass
  self.define_method(:foo) { return "foo" }
end

为什么会这样,这和这有什么不同?

class Klass
  self.define_method(:foo) { return "foo" }
end

(对不起,如果这个问题包含任何错误的假设。就像我说的,我有点困惑。)

4

1 回答 1

9

直接回答你的问题:Module#define_method创建一个实例方法。“类方法”是对象的单例类(或特征类)上的实例方法Class。我敢肯定这听起来很令人困惑。让我解释一下为什么 Ruby 首先包含“单例类”的概念:

首先,让我说不同面向对象语言的基本“框架”是多种多样的。Ruby 在对象、类、元类等方面的设计绝不是唯一可能的设计,该语言可以以不同的方式设计。话虽如此,Ruby 以它的方式工作是有逻辑的原因的。我会尽量简明扼要地解释...

考虑一个简单的方法调用,例如:

[1,2,3].first

在这里,我们调用了一个名为 的方法first,其中一个Array对象作为接收者。为了处理这个方法调用,Ruby 需要搜索匹配的方法定义并执行它。它从哪里开始寻找?自然,在 的实例方法中Array。如果在那里没有找到,它会在Array's 的超类中查找,然后是超类的超类,以及Module混入的 sArray或其超类等。

“基于类”(与基于原型相反)的面向对象语言或多或少都以这种方式工作。如果您曾经使用 Java、C++ 或 Python 进行过编程,那么您应该对这种行为很熟悉。

现在,Ruby 的创建者还希望能够为一个对象添加方法。在基于原型的 OO 语言中,这很容易,但它如何在基于类的语言中工作?他通过引入“单例类”或“特征类”的概念使之成为可能。

简单地说,“单例类”是只有一个实例的类。我相信,与其尝试为每个对象跟踪不同的单例类,Ruby 会等到您第一次尝试访问对象的单例类,然后创建该类并将其动态插入到对象的继承链中。

正如我刚才所说,当一个方法被调用时,Ruby首先在对象的类中查找匹配的定义,然后是超类等。由于单例类作为对象继承链中的第一个链接插入,因此它们是第一位的Ruby 将寻找方法定义。

引入“单例类”的概念同时也解决了另一个问题。在 Java 中(例如),您可以定义static在类上调用的方法。在 Ruby 中,人们经常想做类似的事情。使用“单例”类和方法,您可以做到这一点:您所要做的就是在 Class 对象上定义一个单例方法。

(请记住,在 Ruby 中,类也是对象。这就是为什么“单例”类和方法的概念可以“用 1 块石头杀死 2 只鸟”的原因,正如我在上面解释的那样!)

额外的信息:

一开始,我提到了“实例方法”。我不知道这是否会令人困惑,或者您是否已经知道“实例方法”是什么。当你定义一个 Ruby 类时,像这样......

class MyClass
  def my_method
    # do something
  end
end

...然后my_method作为. MyClass当 Ruby 在对象的类、超类等中搜索方法定义时,它实际查看的是它们的实例方法。所以一个对象的“方法”就是它的类的实例方法,加上超类的实例方法、超类的超类等等。

关于单例类如何与 Ruby 中的方法查找交互,有一点我上面没有提到的不一致。如果你想详细了解:

类对象的单例类的处理方式与一般其他对象的单例类略有不同。如果您有一个A从另一个类继承的类B,并且B具有单例方法,A则不仅会继承实例方法,还会继承的单例方法B。换句话说,B的单例类被视为 的单例类的超A类。这不适用于任何其他对象的单例类。

于 2012-09-14T19:55:07.697 回答