是否可以混合模块方法?

Posted

技术标签:

【中文标题】是否可以混合模块方法?【英文标题】:Is it possible to mix-in a module method? 【发布时间】:2020-05-02 19:24:36 【问题描述】:

假设我有一个声明模块方法的模块(不是实例方法):

module M
  def self.foo
    puts 'foo'
  end
end

现在假设我想将M.foo 混合到另一个类C 中,这样C.foo 就被定义了。

最后,我想这样做不改变M.foo 的定义方式 并且不只是在C 中创建一个调用M.foo 的方法。 (即将foo重写为实例方法不算数。使用module_function也不算数。)

这在 Ruby 中是不可能的吗?

【问题讨论】:

没有。如果您的意图是在类C 中混合成为类方法的方法,则必须使模块中的方法成为实例方法并使用C.extend M(或C.singleton_class.include M)。 (见Object#extend)。要使用模块方法,您必须调用定义它的模块上的方法,模块Math 的方法就是一个例子。 @CarySwoveland 完美答案!谢谢。 作为学术练习,您可以将M 上的所有类方法复制到实例方法中,但最好只修改M 以首先将定义作为实例方法并可能@ 987654337@如果需要(或使用module_method 【参考方案1】:

我想这样做不改变M.foo 的定义方式

很遗憾,这是不可能的。 Ruby 只允许包含模块,而不是类。 foo 是在 M 的单例类上定义的,一个类。因此,您不能include 它。同样的限制适用于extend。尝试这样做会导致TypeError

module M
  def self.foo
    puts 'foo'
  end
end

class C
  extend M.singleton_class # TypeError: wrong argument type Class (expected Module)
end

但是,您可以通过将 foo 定义为单独模块中的实例方法来实现您想要的,然后可以通过 extend 将其混合到 MC 中:(该模块没有嵌套在M)

module M
  module SingletonMethods
    def foo
      puts 'foo'
    end
  end

  extend SingletonMethods     # <- this makes foo available as M.foo
end

class C
  extend M::SingletonMethods  # <- this makes foo available as C.foo
end

或者使用 Ruby 的 included 回调使用一些元编程魔法:

module M
  module SingletonMethods
    def foo
      puts 'foo'
    end
  end

  extend SingletonMethods

  def self.included(mod)
    mod.extend(SingletonMethods)
  end
end

class C
  include M
end

这是 ActiveSupport::Concern 在 Rails 中工作方式的简化版本。

【讨论】:

一个不错的简单答案,谢谢。这基本上是我在阅读 MRI 源后得出的结论——很高兴在这里以“官方”形式记录它。 @pje 你的问题启发了我问这个问题:***.com/q/59766403/477037 多么有趣的问题啊!我以前从没想过。

以上是关于是否可以混合模块方法?的主要内容,如果未能解决你的问题,请参考以下文章

将 typescript 定义文件与 nodejs 混合需要内部模块中的多个文件

是否可以将 kubeflow 组件与 tensorflow 扩展组件混合使用?

使用模块模式时的 Javascript 混合

Firebase:混合 C++ 和 Objective-C SDK 可以吗?

keil4 下 c语言和汇编语言。混合编程的方法。

JS面向对象基础讲解(工厂模式构造函数模式原型模式混合模式动态原型模式)