【问题标题】:How can I call a class method on its instance?如何在其实例上调用类方法?
【发布时间】:2026-01-05 19:55:01
【问题描述】:

a1A 上的一个方法。

module A
  def self.a1
    puts "I am defined in A"
  end
end

class Sample
  include A
end

samp = Sample.new

如何拨打samp.a1

puts samp.a1

【问题讨论】:

    标签: ruby oop


    【解决方案1】:

    这里有几件事要记住:

    • 如果您声明带有 self 前缀的模块方法,这意味着它们可以直接在模块上调用,例如 A.a1,但这也意味着它们不会被导入与include。那些没有 self 声明的是“混合方法”,或者那些将在include 上自动导入的方法。
    • 如果您include 多个模块定义了一个方法,那么最后包含的模块将是实际被调用的模块。

    这里的解决方法是将def self.a1 中的def a1 更改为module A,或者直接使用A.a1 调用它。如果 B 还定义了a1,那么它将具有优先级除非您首先include B,使其优先级较低。

    【讨论】:

    • 很多教程让Ruby mixins 变得异常复杂,我真的不明白为什么。 include 使 mixin 成为超类。就是这样。关于 Ruby 混合,实际上没有什么需要了解的了。这只是标准无聊的旧继承。
    • @JörgWMittag 令人困惑的是,如果您从未使用过允许这种选择性组合的语言。大多数人习惯于单继承或多继承,而这些通常在定义时就被锁定了。使用include,您可以随时任意添加额外的“超类”类型继承。起初这似乎很奇怪,就像您如何也可以对单个对象执行此操作一样。
    【解决方案2】:

    如果您知道这种事情会提前发生,您可以在包含模块时使用别名(请注意,这会将方法定义从 def self.a1 更改为 def a1,以便它们被正确包含为实例方法):

    module A
      def a1
        puts "I am defined in A"
      end
    end
    
    module B
      def a1
        puts "I am defined in B"
      end
    end
    
    class Sample
      include A
      alias :a_a1 :a1
      include B
      alias :b_a1 :a1
    end
    
    samp = Sample.new
    samp.a_a1
    samp.b_a1
    samp.a1
    

    运行此输出:

    I am defined in A
    I am defined in B
    I am defined in B
    

    不过,作为一般规则,如果可以的话,我会避免这种情况并重命名模块中的一个方法;尽管有时您出于某种原因无法做到这一点。

    【讨论】:

      【解决方案3】:

      如果它只是用于 a1,那么这应该可以工作:

      class Sample
        include A
        def a1
          self.class.a1
        end
      end
      

      如果所有方法都需要它,您可以尝试使用类的发送命令捕获 NoMethodError,但这通常是多余的。

      【讨论】:

      • 这不适用于include - 您需要改为extend