Ruby 中的“include”和“prepend”有什么区别?

问题描述 投票:0回答:2

来自模块

Module#append_features(mod) → mod

当此模块包含在另一个模块中时,Ruby 会调用此模块中的append_features,并将其传递给mod 中的接收模块。 Ruby 的默认实现是 添加 将此模块的常量、方法和模块变量添加到 mod(如果该模块尚未添加到 mod 或其祖先之一)。

Module#prepend_features(mod) → mod

当这个模块被添加到另一个模块中时,Ruby 会调用 prepend_features 在这个模块中,将其传递给mod中的接收模块。 Ruby 的默认设置 实现是覆盖常量、方法和模块 如果该模块尚未被修改,则修改该模块的变量 添加到 mod 或其祖先之一。

谁能帮助我理解以下问题:

  • 除了默认的功能外,

    Module
    还有哪些功能被定义为
    append
    prepend

  • 它们在功能上有何不同?

  • 何时使用

    append_features
    以及何时使用
    prepend_features

  • 上面两条粗线有什么区别?

ruby mixins prepend ruby-2.0
2个回答
45
投票
  • Module 的哪些功能被定义为追加和前置?

正如您引用的文本中所指定的:

常量、方法和模块变量

  • 它们在功能上有何不同?

两者都将混合模块的方法添加到传递的模块(类)中。区别在于这些方法的查找顺序,如果目标类已经定义了它们:

include
的行为就好像目标类继承了混合模块:

module FooBar
  def say
    puts "2 - Module"
  end
end

class Foo
  include FooBar

  def say
    puts "1 - Implementing Class"
    super
  end
end

Foo.new.say # =>
            # 1 - Implementing Class
            # 2 - Module

prepend
使混合模块中的方法“更强”并首先执行它们:

module FooBar
  def say
    puts "2 - Module"
    super
  end
end

class Foo
  prepend FooBar

  def say
    puts "1 - Implementing Class"
  end
end

Foo.new.say # =>
            # 2 - Module
            # 1 - Implementing Class

这个例子是从这里抄来的:http://blog.crowdint.com/2012/11/05/3-killer-features-that-are-coming-on-ruby-2-0.html

  • 何时使用append_features,何时使用prepend_features?

当您想将目标模块(类)的方法保留在方法查找链的末尾时,请使用

prepend

通过搜索

ruby
module
prepend
可以找到一些现实世界的示例:

(注意:我只提到方法,因为它们在继承和混合方面最容易想象,但这同样适用于其他功能。)


8
投票

我想将其添加为@Mladen Jablanovic 已经做出的好答案的评论,但由于我的声誉较低,我不能这样做。

我在此处的帖子中找到了更简洁、更清晰和更具描述性的答案 - Ruby 模块:包含 vs Prepend vs Extend,我将其发布在这里,以防万一有人需要它并且可以轻松获得它。

直接引用:

虽然 include 是将外部代码导入到类中的最常见方法,但 Ruby 还提供了另外两种方法来实现这一点:extend 和 prepend。然而,它们根本没有相同的行为,并且这些差异经常被 Ruby 开发人员误解。

要了解如何使用它们,我们必须首先更深入地了解 Ruby 如何使用称为祖先链的东西来解析要在运行时执行的方法。

当创建 Ruby 类时,它会保存一个常量名称列表,这些常量名称是其祖先。它们是该类继承的所有类,以及它们包含的模块。例如,通过调用 String 类的祖先,我们可以获得其祖先的列表:

String.ancestors
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]

include 是最常用且最简单的导入模块代码的方法。当在类定义中调用它时,Ruby 会将模块插入到类的祖先链中,就在其超类之后。

自 Ruby 2 起可用,对于 Ruby 爱好者来说,prepend 比它的另外两个朋友不太了解。它实际上像 include 一样工作,只不过不是将模块插入链中的类及其超类之间,而是将其插入到链的底部,甚至在类本身之前。

我建议阅读这篇文章以更好地理解它,因为它附带了示例。

© www.soinside.com 2019 - 2024. All rights reserved.