【问题标题】:What are the practical differences between a module method and a class method in Ruby?Ruby 中的模块方法和类方法之间的实际区别是什么?
【发布时间】:2016-11-19 08:11:21
【问题描述】:

两者有什么区别

module Logging
  def self.log
    if @logger.nil?
      @logger = Logger.new STDOUT
    end
    @logger
  end
end

还有这个?

class Logging
  def self.log
    if @logger.nil?
      @logger = Logger.new STDOUT
    end
    @logger
  end
end

他们似乎都在做同样的事情。为什么我会选择一个而不是另一个?

【问题讨论】:

标签: ruby class module


【解决方案1】:

tl;dr:Ruby 中没有类方法和模块方法,只有实例方法。考虑到它们都是实例方法,因此是相同的东西,不可能有任何区别。


Ruby 中没有“类方法”或“模块方法”之类的东西。 Ruby 只有一种方法:实例方法。

我们在谈到某种使用实例方法的模式时,有时出于方便使用“类方法”或“模块方法”,但没有这样的Ruby 中的概念。 “类方法”和“模块方法”实际上只是对象的单例方法,恰好是 Module 类或 Class 类的实例。恰好是ClassModuleStringArrayArrayHashObjectFoo、@987654331 的实例的对象的单例方法之间绝对没有任何区别@、WhateverGarbledigookidoo

哦。我提到了吗?单例方法也不存在。同样,它是我们用于某些类型的方法用法的词,但它们实际上只是对象的单例类的常规无聊的旧实例方法。

但是,“foo的单例类的实例方法”和“Foo的单例类的实例方法,其中FooClass的一个实例”真的很长,所以我们缩短出于方便,他们将它们改为“foo 的单例方法”和“Foo 的类方法”,完全了解那些实际上并不存在的虚构语言。

与具有三种不同方法(实例方法、静态方法和构造函数(有点像方法))的 Java 不同,Ruby 只有一种方法:实例方法。没有类方法,没有模块方法,没有全局方法,没有顶级方法,没有静态方法,没有构造函数。但是,它确实具有三种类:常规类、单例类和包含类(后者是在您调用 include 或 @987654341 时被合成并注入到继承层次结构中的类@)。这些类的主要区别在于Object#classClass#superclassClass#ancestors 等方法是显示它们还是抑制它们。单例类被所有它们抑制,包括前两个类,但由ancestors 显示。

【讨论】:

  • 如果它不存在,你能解释一下什么是类方法吗?如果我调用Math.abs 是在Math 的实例上调用实例方法abs 吗?
  • 不,它是在对象Math上调用Math的单例类中定义的实例方法abs。我无法解释什么是类方法,因为它不存在。我们 Ruby 主义者有时所说的“类方法”只是一个对象的单例方法,它恰好是 Class 类的一个实例。但是单例方法也不作为语言结构存在。它们只是单例类的实例方法。我们只是把它们称为简写。
【解决方案2】:

Jörg Mittag 是正确的,技术上没有类方法或模块方法。但是,我假设“类方法”是指“在类实例的单例类上定义的实例方法”,而“模块方法”是指“在模块实例的单例类上定义的实例方法”。

两者在功能上没有区别。两者都在命名空间中定义了一个方法。

在实践中,您会发现它们往往用于不同的目的。例如,类方法通常用于指定构造对象的不同方式,例如Puzzle.from_textfile。模块方法只是放入单个命名空间的全局函数,因为它们在逻辑上是相关的,例如Math.sinMath.abs

同样需要注意的是,Ruby 也有“模块函数”的概念,这与本题无关。术语“模块函数”是指具有相同私有实例方法的模块上的类方法。这些可以使用Module.module_function 以编程方式创建,并且当一个模块既要用作命名空间又用作mixin(例如Math)时很有用。

【讨论】:

    【解决方案3】:

    模块是关于提供可跨多个类使用的方法 - 将它们视为“库”(就像您在 Rails 应用程序中看到的那样)。类是关于对象的;模块是关于功能的

    this

    【讨论】:

    • 一个只包含模块方法的模块示例(没有实例方法可以通过include-ing 模块与类的实例方法混合)是Ruby 的Math 模块。模块方法有时被称为“辅助”方法。
    【解决方案4】:

    模块与类相似,因为它们包含方法、常量以及其他模块和类定义的集合。与类不同,您不能基于模块创建对象。

    模块有两个用途。首先,它们充当命名空间,让您定义名称不会与其他地方定义的名称冲突的方法。其次,它们允许您在类之间共享功能——如果一个类混合在一个模块中,则该模块的实例方法变得可用,就好像它们已在该类中定义一样。多个类可以混合在同一个模块中,在不使用继承的情况下共享模块的功能。您还可以将多个模块混合到一个类中。

    类是用来创建对象的。

    【讨论】:

    • 一个类include一个模块没有必要调用它的一个模块方法。它们只是直接引用;例如,x = Math.sqrt(2)
    • 哦,是的,感谢您的评论。这种方式也可以
    • 我的意思是当你include一个模块时,只包含实例方法; Ruby 只是跳过了模块方法,所以 include 在这里无关紧要。
    • 这个问题是问模块方法和类方法的区别,而不是模块和类。
    猜你喜欢
    • 2013-03-24
    • 2016-10-31
    • 2015-03-12
    • 2012-08-06
    • 1970-01-01
    • 2017-12-02
    • 2010-11-06
    • 2015-12-11
    • 1970-01-01
    相关资源
    最近更新 更多