“定义方法”在语义上如何工作?

时间:2015-04-28 20:49:59

标签: ruby class object methods object-model

背景:

以下是我对对象模型的理解(相对于我下面的问题):

  • self始终引用当前堆栈帧中的接收器。
  • 当您处于最高级别并且您说def someMethod时,隐式接收器为self并且您正在创建一个位于与self关联的匿名类中的方法。这个匿名类恰好位于Object下面(selfObject类的一个实例)所以当你调用someMethod时,Ruby“向右迈出了一步” ,它落在匿名类中,从而找到并调用您的方法。
  • 这类似于在类定义中定义方法时所发生的情况。如果,在类定义中,您说:def self.classMethod您正在匿名类中创建一个方法,该类位于Class类的下方。此类的方法,当前正在定义的类的“右侧”将不会对新类的实例可见。

我的问题:

“在类中定义方法”如何首先发生?(语义上)

Class对象不应该与普通对象不同,对吗?

根据我对消息处理的理解,Class对象有一个表作为其状态的一部分,可能意味着它是一个实例变量,它具有所有实例方法的名称。这是方法查找的工作方式。 (如果Ruby没有找到它,它会一次又一次地上升,可能是指链上一个链接的方向是当前Class对象状态的一部分。)

由于Ruby并不真正关心对象类型,我认为它并不关心它在查找方法时特意查看Class对象。相反,它只是跟随引用并查找具有某些名称的状态位。那么,我可以创建自己的“类对象”而不使用不从Class类继承的class关键字吗?

如果这个问题没有任何意义,那么我道歉。我只想知道当口译员遇到def关键字时会发生什么。

1 个答案:

答案 0 :(得分:2)

当你写下“克服某些东西”时。在ruby中,您正在向模块添加方法。有时候,这个模块是一个类“' (一种模块)。这完全取决于什么是自我'当时是:

class Foo

  # right now self is 'Foo'

  class << self
    # right now self is 'Class:Foo'
  end

  def self.bar
    # right now self is 'Foo'
  end

end

def Foo.buz
  # right now self is 'Foo'
end

obj = Foo.new

def obj.baz
  # right now self is 'Foo:0x007fe8a632fa78' (an instance)
end

一个类只是一种模块。子类化是从一个模块到另一个模块创建指针的一种方法:

class Foo
end

class Bar < Foo
end

> Bar.ancestors
=> [Bar, Foo, Object, Kernel, BasicObject]

另一种方法是包括mixins:

module Mixin
end
class Foo
  include Mixin
end

> Foo.ancestors
=> [Foo, Mixin, Object, Kernel, BasicObject]

方法调度适用于继承链中存在的内容。它是父模块的列表(不是树),并根据创建继承的时间进行排序:

# bar.rb

module MixinA
  def something
    puts "MixinA"
    super
  end
end

module MixinB
  def something
    puts "MixinB"
  end
end

class Base
  def something
    puts "Base"
    super
  end
end

class Sub < Base
  include MixinB
  include MixinA
  def something
    puts "Sub"
    super
  end
end

obj = Sub.new
obj.something

执行命令

$ ruby bar.rb
Sub
MixinA
MixinB

检查链条:

> Sub.ancestors
=> [Sub, MixinA, MixinB, Base, Object, Kernel, BasicObject]

当在此列表的行列中发生方法调用时,会查找相关方法。如果链中没有任何模块具有该方法,则搜索从顶部开始,而是调用 method_missing 。在任何一种情况下,第一个决议都获胜。

Yehuda Katz在2009年写了一篇关于这篇文章的好文章: