【问题标题】:What is the difference between 'include' and 'prepend' in Ruby?Ruby 中的“包含”和“前置”有什么区别?
【发布时间】:2013-03-01 07:16:26
【问题描述】:

来自Module

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

Module#prepend_features(mod) → mod => 当这个模块被前置在另一个模块中时,Ruby 在这个模块中调用 prepend_features,将它传递给 mod 中的接收模块。如果此模块尚未添加到 mod 或其祖先之一,则 Ruby 的默认实现是将此模块的常量、方法和模块变量覆盖到 mod。

谁能帮我理解以下问题:

  • Module 的哪些功能除了默认的之外还定义为appendprepend

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

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

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

【问题讨论】:

    标签: ruby mixins prepend ruby-2.0


    【解决方案1】:

    我想将它作为评论添加到@Mladen Jablanovic 已经提出的一个很好的答案中,但由于我的声誉点低,我不能这样做。

    我在此处的帖子中找到了更简洁、更清晰和更具描述性的答案 - Ruby modules: Include 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 开始,prepend 对 Rubyists 的了解比它的其他两个朋友要少一些。它实际上像 include 一样工作,只是它不是在链中的类和它的超类之间插入模块,而是将它插入到链的底部,甚至在类本身之前。

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

    【讨论】:

      【解决方案2】:
      • Module 的哪些功能被定义为 append 和 prepend?

      如您引用的文本中所述:

      常量、方法和模块变量

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

      两者都将混入模块的方法添加到传递的模块(类)中。不同之处在于这些方法的查找顺序,以防目标类已经定义了它们:

      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

      通过搜索 rubymoduleprepend,可以找到一些真实世界的示例:

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

      【讨论】:

      • +1 给你。来自文档Ruby’s default implementation is to add the constants, methods, and module variables of this module 。现在可以了。除了这些还有其他功能吗?
      • 你在这里给出了很好的解释。你能看看我的最后一个问题和更新的第一个问题吗?
      • 1) 仅此而已,(只是?!)常量、方法和模块变量。 4) 与 2) 基本相同,并通过示例进行说明。
      • 感谢您的努力和时间帮助我理解。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 2011-06-10
      • 1970-01-01
      • 2011-03-15
      • 2010-09-06
      • 2010-11-17
      • 1970-01-01
      相关资源
      最近更新 更多