Ruby中的模块方法和类方法有什么实际区别?

时间:2016-07-16 03:59:53

标签: ruby class module

之间有什么区别
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

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

5 个答案:

答案 0 :(得分:4)

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

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

在讨论使用实例方法的某种模式时,我们有时会使用 word “类方法”或“模块方法”,但是没有这样的Ruby中的概念。 “类方法”和“模块方法”实际上只是对象的单例方法,恰好是Module类或Class类的实例。对象的单例方法(恰好是ClassModuleStringArrayHash的实例之间绝对没有区别, ObjectFooBarWhateverGarbledigookidoo

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

但是,“foo的单例类的实例方法”和“{1}}的单例类的实例方法,其中FooFoo的实例”真的很长,所以我们将它们缩短为“Class的单一方法”和“foo的类方法”,方便了解完全正确那些是实际上并不存在于该语言中。

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

答案 1 :(得分:2)

JörgMittag是正确的,技术上没有类方法或模块方法。但是,我将假设“类方法”表示“在类实例的单例类上定义的实例方法”,而“模块方法”则表示“在Module实例的单例类上定义的实例方法”。 / p>

两者之间没有功能差异。两者都在命名空间中定义方法。

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

同样重要的是要注意Ruby也有“模块功能”的概念,这与这个问题无关。术语“模块功能”是指模块上的类方法,该模块具有相同的私有实例方法。这些可以使用Module.module_function以编程方式创建,并且在将模块用作命名空间和mixin(例如Math)时非常有用。

答案 2 :(得分:1)

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

请参阅this

答案 3 :(得分:0)

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

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

类是为了创建对象。

答案 4 :(得分:0)

您想了解Ruby中的类和实例方法之间的差异。

看到不同的行为很重要。忽略下面的类语法并关注功能,尤其是调用两种方法类型的方式。

下面是一个包含两个方法的类,第一个是类方法,第二个是实例方法。

class Invoice
  # Class method
  def self.print_out
    "Printed out Invoice"
  end
  # Instance method
  def convert_to_pdf
    "Converted to PDF"
  end
end

如果您注意到,语法的唯一区别在于我使用世界 self ,用于类方法,并使用名称本身作为实例方法。

现在,当我想调用类方法时,我能够通过(。)声明类的名称,然后是方法名,如下所示:

class Invoice
  # Class method
  def self.print_out
    "Printed out Invoice"
  end
  # Instance method
  def convert_to_pdf
    "Converted to PDF"
  end
end

Invoice.print_out

继续将此代码复制并粘贴到Repl.it中,您将看到结果。

如果我尝试使用相同的语法调用实例方法,则会抛出错误:

class Invoice
 # Class method
  def self.print_out
    "Printed out Invoice"
  end
  # Instance method
  def convert_to_pdf
    "Converted to PDF"
  end
end

Invoice.convert_to_pdf

再次,将其复制并粘贴到Repl.it,您将看到错误,应该说 convert_to_pdf 是一种未定义的方法。要运行实例方法,我们需要创建该类的实例来运行它。

您需要像这样实例化一个新的发票

i = Invoice.new
i.convert_to_pdf

在Repl.it中运行此方法时,它会打印消息而不会出现错误。试试吧。

现在,如果我尝试以与调用实例方法相同的方式访问我的类方法,则会导致错误。

因此,可以结合类的名称调用类方法,而实例方法要求您创建一个实例来调用该方法。

现在,话虽如此,我实际上可以将我的代码快捷一点,以便在与类名相同的行上调用我的实例方法:

Invoice.new.convert_to_pdf

这将正常工作。但是,通常以这种方式调用方法是没有意义的,因为您无法对其进行太多操作。因此,访问实例方法的早期方法更好。

那么,为什么在调用类方法时更容易使用实例方法呢?

让我们想象你班上有15种方法,你不想在你的课程中多次打电话给班级。我不会在这里提供一个例子,因为写一些没用的东西会太难看和耗费时间。

每次打电话给班级都不好看,被认为是糟糕的编程习惯。从本质上讲,这是在程序中创建15个新对象。

创建实例变量并使用它调用所有方法是一种更好的做法。

这样您每次都不会创建该类的新实例,而是为所有方法使用相同的实例。

这些是Ruby中可用的不同类型的方法以及如何调用它们。