【问题标题】:How can I declare a mixin method such that it's usable from both instance methods and class methods?如何声明一个 mixin 方法,以便它可以从实例方法和类方法中使用?
【发布时间】:2011-11-25 20:27:00
【问题描述】:

我想在 Ruby 模块中放置一个方法,以便可以使用简单的语法从类方法实例方法调用它:

module MyMod
  def fmt *args
    args.map { | a | "You said #{a}" }
  end
end

class MyClass
  include MyMod
  def inst
    puts fmt 1,2,3
  end
  def self.cls
    puts fmt 4,5,6
  end
end

上面的不行,因为类方法(cls)看不到实例方法fmt。如果我将定义更改为self.fmt,则实例方法必须将其调用为MyMod.fmt

我希望能够从这两种方法中调用fmt (some stuff)。有没有“红宝石”的方式来做到这一点?我可以将模块定义为

module MyMod
  def self.fmt *args
    args.map { | a | "You said #{a}" }
  end
  def fmt *args
    MyMod.fmt args
  end
end

但这不是很干燥,是吗?有没有更简单的方法?

【问题讨论】:

    标签: ruby module mixins


    【解决方案1】:

    您可以利用Module#included 方法的优势来做到这一点:

    module MyMod
      # here base is a class the module is included into
      def self.included(base)
        # extend includes all methods of the module as class methods
        # into the target class
        base.extend self
      end
    
      def fmt(*args)
        args.map { |a| "You said #{a}" }
      end
    end
    
    class MyClass
      # regular include provides us with instance methods
      # and defined above MyMod#included hook - with class methods
      include MyMod
    
      def inst
        puts fmt(1, 2, 3)
      end
    
      def self.cls
        puts fmt(4, 5, 6)
      end
    end
    
    puts MyClass.cls
    puts MyClass.new.inst
    

    这是输出:

    You said 4
    You said 5
    You said 6
    
    You said 1
    You said 2
    You said 3
    

    更详细的解释请看this article

    【讨论】:

    • 当构建某种 DSL 的东西时,该回调很好,其他开发人员应该将其包含在他们的类中。否则,这有点太神奇了,因为目前尚不清楚使用include 是否会导致添加类方法。因此,如果这是在内部代码中,手动使用 extend 本身几乎总是有益的,而不是经历记录这种特殊行为的麻烦。
    • 好点子,但如果你想在多个地方使用这个模块,我不认为在你需要的地方同时调用includeextend 是一个好的解决方案。
    • @KL-7,为什么不呢?该模块正在为您执行此操作……您不必这样做。无论如何,这是唯一的方法。
    • 这正是我们正在讨论的内容,模块是否应该“为您做这些”。而且它是“唯一的方式”显然是错误的,因为仍然存在“手动”方式......
    • 完全错过了第一条评论,抱歉 ;)
    【解决方案2】:

    includeextendMyMod 模块都在 MyClass 中,以便将 fmt 方法作为实例和类方法添加到 MyClass

    Object#extend 所做的是将模块的方法添加到单个实例中。在这种情况下,该实例就是类本身,这就是方法将作为类方法可用的原因。

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-06
      相关资源
      最近更新 更多