【问题标题】:How does 'defining a method' work semantically?“定义方法”在语义上是如何工作的?
【发布时间】:2015-07-07 21:47:33
【问题描述】:

背景:

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

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

我的问题:

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

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

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

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

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

【问题讨论】:

  • 不继承自Class 的类对象会是什么?这不就是任何其他对象吗?
  • @DaveNewton 是的。这就是为什么我把它放在双引号中。我在问你是否可以创建一个行为类似于Class 对象的普通对象,并且隐含地询问这样做会涉及什么.....再次,这只是为了理解它的真正含义定义一个方法”
  • 您可以使用Class.new(superclass = nil) 创建一个类对象,如果您检查Class.new.class.superclass,您可以确定Class 继承自Module - 这是它获得大部分功能的地方。
  • 如果你真的想要,你很可能扩展 Module 来创建一个类对象。

标签: ruby class object methods object-model


【解决方案1】:

当您在 ruby​​ 中编写 'def something' 时,您正在向模块添加一个方法。有时该模块是一个“类”(一种模块)。这完全取决于当时的“自我”是什么:

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]

另一种方法是包含混合:

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 年写了一篇关于这方面的好文章:

【讨论】:

    猜你喜欢
    • 2012-04-18
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 2017-05-18
    • 2015-12-11
    • 2023-04-09
    • 2023-03-22
    相关资源
    最近更新 更多