【问题标题】:On ruby, why include is private and extend is public?在 ruby​​ 上,为什么 include 是私有的,而 extend 是公共的?
【发布时间】:2011-05-11 23:02:57
【问题描述】:

在 ruby​​ 上,include 是私有的,而 Object#extend 是公开的原因是什么?

【问题讨论】:

    标签: ruby metaprogramming language-design access-specifier


    【解决方案1】:

    Object#extend 必须公开,否则您将无法使用它。毕竟,它的目的是把一个模块混入一个对象中,所以你通常会称它为obj.extend(Foo),这对于私有方法是不可能的。

    Module#include 通常只在模块体内使用,如下所示:

    class Bar
      include Foo
    end
    

    即它通常在没有接收者的情况下调用,因此不必公开。当然,它也没有必须是私有的。

    我的猜测是它是私有的原因是它更具侵入性,因为它改变了Bar每个 实例的行为,而Object#extend 只改变了一个对象。因此,Module#include 在某种意义上“更危险”,因此被设为私有。

    我不知道这是否是真正的原因,但它与Module#define_method等其他类似方法一致。

    【讨论】:

    • 它没有必须。如果它是私有的,您将能够使用它:obj.send(:extend, Foo)obj.instance_eval{ extend Foo },不包括模块 class Bar; extend Foo; end 的情况
    • @Marc-AndréLafortune:当然是class << obj; extend Foo; end。就像我说的,这只是一个猜测。
    • 我在回复你的第一句话“Object#extend 必须是公开的,否则你将无法使用它。”
    • PS:我想不出有任何一种情况会像您的评论那样使用class << obj; extend Foo; end
    • 快进到 2014 年。Module#include(和 Module#prepend)在 v2.1 中公开。
    【解决方案2】:

    能够在任何时候运行Foo.include(Bar) 很可能是非常讨厌的错误的来源。

    【讨论】:

      【解决方案3】:

      为了补充 Jörg W Mittag 的回答,Object#extend 也可用于包含要在类级别使用的模块实例方法(该类的所有实例也可以使用):

      module Foo
        def bar (baz)
        end
      end
      
      class Qux
        extend Foo
      
        bar 'asdf'
      end
      

      【讨论】:

        猜你喜欢
        • 2023-04-04
        • 2023-03-26
        • 2017-04-02
        • 2013-07-26
        • 1970-01-01
        • 2019-02-18
        • 1970-01-01
        • 1970-01-01
        • 2017-12-28
        相关资源
        最近更新 更多