Ruby,将方法添加到模块,类或对象

撕裂

在添加Kernel使它们在全球范围内可用的方法时,我发现有些奇怪这很有趣,我正在寻找一些文档或很好的解释。

让我们看一下代码:

文件:./ demo.rb

# example 1

module Kernel
  def foo
    puts "I'm defined inside the module!"
  end
end


# example 2

module Bar
  def bar
    puts "I'm included! (bar)"
  end
end

Kernel.send :include, Bar


# example 3

module Baz
  def baz
    puts "I'm included! (baz)"
  end
end

module Kernel
  include Baz
end

然后,在bash和IRB中

$ irb -r ./demo.rb
> foo
# I'm defined inside the module!
> bar
# NameError: undefined local variable or method `bar' for main:Object
> baz
# NameError: undefined local variable or method `baz' for main:Object
>
> self.class.ancestors
# => [Object, Kernel, BasicObject] 
>
> include Kernel
>
> self.class.ancestors
# => [Object, Kernel, Baz, Bar, BasicObject]
>
> foo
# I'm defined inside the module!
> bar
# I'm included! (bar)
> baz
# I'm included! (baz)

foo可以正常工作,并且可用于包含的所有对象Kernelbar并且baz,在另一方面,不能立即使用。
我想这是因为IRB(an 评估上下文Object已经包含Kernel,并且在模块B内包含模块A不会“重新加载” B的所有先前包含的内容。
好的,这是很合理的,事实上,重新包含Kernel将添加其他两种方法。

然后,我的问题是:

  1. 为什么开放 Kernel工作?(示例1)
  2. 如果打开模块的处理方式有所不同,为什么第三个示例也不起作用?
最大限度

foo.bar在Ruby中调用会发生什么像这样:

foo.class.ancestors.each do |klass|
  if klass.public_instance_methods.include? :bar
    return klass.instance_method(:bar).bind(foo).call
  end
end
raise NameError

即Ruby在祖先中搜索以找到匹配的实例方法。

当您调用A.include BRuby时会发生什么像这样:

B.ancestors.each do |mod|
  A.ancestors << mod unless A.ancestors.include? mod
end

B并且它的所有祖先都成为了祖先A这两种行为可以解释一切:

  1. 开放是Kernel有效的,因为它包含在Object每个对象中,因此它是每个对象的祖先,这意味着只要您在任何对象上调用方法,都可以搜索它的方法(包括新方法)。
  2. 打开模块没有区别。您的第二个和第三个示例实际上是相同的。它们都无效,因为Kernel仅在包含时才搜索祖先,这是在您添加新祖先之前。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

将调用方法的对象添加到列表中

来自分类Dev

将模块目录添加到@INC

来自分类Dev

将子类对象添加到超类列表

来自分类Dev

在Ruby中,将方法添加到实例的singleton类的用例是什么?

来自分类Dev

将@property方法添加到类

来自分类Dev

将方法添加到创建的类C ++中

来自分类Dev

将__getitem__添加到模块

来自分类Dev

将类添加到辅助方法调用

来自分类Dev

Ruby将方法添加到类

来自分类Dev

将扩展模块添加到groovy类

来自分类Dev

将值添加到Ruby JSON对象

来自分类Dev

使用jQuery将类添加到DOM对象数组中的正确方法是什么?

来自分类Dev

将节点模块添加到gitignore

来自分类Dev

将Java类方法添加到新线程中

来自分类Dev

将child中定义的方法设置为Parent类引用或将其添加到父对象

来自分类Dev

将类添加到对象1,等待,在for循环中将类添加到对象2

来自分类Dev

在运行时将类添加到Ruby模块

来自分类Dev

将C本机方法添加到预先存在的Ruby类中

来自分类Dev

将元类级别添加到C ++对象模型

来自分类Dev

将行为添加到外部模块返回的对象的pythonic方法是什么?

来自分类Dev

通过模板参数将方法添加到类

来自分类Dev

将方法添加到创建的类C ++中

来自分类Dev

将内容添加到父类的Update方法

来自分类Dev

将setter方法添加到Scala类

来自分类Dev

将扩展模块添加到groovy类

来自分类Dev

将ActiveModel错误添加到ruby类

来自分类Dev

python将类对象添加到列表

来自分类Dev

为什么类外部包含的模块将实例方法添加到类的对象

来自分类Dev

用反射将未知类的对象添加到ArrayList