Ruby 简明教程

Ruby - Modules and Mixins

模块是将方法、类和常量分组在一起的一种方式。模块给您带来了两大好处:

Modules are a way of grouping together methods, classes, and constants. Modules give you two major benefits.

  1. Modules provide a namespace and prevent name clashes.

  2. Modules implement the mixin facility.

模块定义了一个名称空间,一个沙盒,您可以在其中使用您的方法和常量,而不用担心被其他方法和常量踩到。

Modules define a namespace, a sandbox in which your methods and constants can play without having to worry about being stepped on by other methods and constants.

Syntax

module Identifier
   statement1
   statement2
   ...........
end

模块常量的命名方式与类常量相同,以大写字母开头。方法定义看起来也很相似:模块方法的定义方式与类方法相同。

Module constants are named just like class constants, with an initial uppercase letter. The method definitions look similar, too: Module methods are defined just like class methods.

与类方法一样,您可以通过在方法名称前面加上模块名称和一个句点来调用模块方法,并且可以使用模块名称和两个冒号来引用常量。

As with class methods, you call a module method by preceding its name with the module’s name and a period, and you reference a constant using the module name and two colons.

Example

#!/usr/bin/ruby

# Module defined in trig.rb file

module Trig
   PI = 3.141592654
   def Trig.sin(x)
   # ..
   end
   def Trig.cos(x)
   # ..
   end
end

我们可以使用相同的函数名称但不同的功能来定义另一个模块:

We can define one more module with the same function name but different functionality −

#!/usr/bin/ruby

# Module defined in moral.rb file

module Moral
   VERY_BAD = 0
   BAD = 1
   def Moral.sin(badness)
   # ...
   end
end

与类方法一样,在模块中定义方法时,您需要指定模块名称,后跟一个点,然后再指定方法名称。

Like class methods, whenever you define a method in a module, you specify the module name followed by a dot and then the method name.

Ruby require Statement

require 语句类似于 C 和 C++ 的 include 语句,以及 Java 的 import 语句。如果第三方程序想要使用任何已定义的模块,它只需使用 Ruby require 语句加载模块文件即可:

The require statement is similar to the include statement of C and C++ and the import statement of Java. If a third program wants to use any defined module, it can simply load the module files using the Ruby require statement −

Syntax

require filename

这里,不需要给文件名称加上 .rb 扩展名。

Here, it is not required to give .rb extension along with a file name.

Example

$LOAD_PATH << '.'

require 'trig.rb'
require 'moral'

y = Trig.sin(Trig::PI/4)
wrongdoing = Moral.sin(Moral::VERY_BAD)

在这里,我们使用 $LOAD_PATH << '.' 使 Ruby 了解到包含的文件必须在当前目录中搜索。如果您不想使用 $LOAD_PATH,则可以使用 require_relative 从相对目录包含文件。

Here we are using $LOAD_PATH << '.' to make Ruby aware that included files must be searched in the current directory. If you do not want to use $LOAD_PATH then you can use require_relative to include files from a relative directory.

IMPORTANT - 在此,两个文件都包含相同的函数名称。因此,这将在包含到调用程序时导致代码歧义,但模块避免了这种代码歧义,我们能够使用模块名称调用适当的函数。

IMPORTANT − Here, both the files contain the same function name. So, this will result in code ambiguity while including in calling program but modules avoid this code ambiguity and we are able to call appropriate function using module name.

Ruby include Statement

您可以将模块嵌入到类中。要将模块嵌入到类中,您可以在类中使用 include 语句:

You can embed a module in a class. To embed a module in a class, you use the include statement in the class −

Syntax

include modulename

如果模块在一个单独的文件中定义,那么在将模块嵌入到类中之前需要使用 require 语句包含该文件。

If a module is defined in a separate file, then it is required to include that file using require statement before embedding module in a class.

Example

考虑 support.rb 文件中编写的以下模块。

Consider the following module written in support.rb file.

module Week
   FIRST_DAY = "Sunday"
   def Week.weeks_in_month
      puts "You have four weeks in a month"
   end
   def Week.weeks_in_year
      puts "You have 52 weeks in a year"
   end
end

现在,您可以按如下所示在课堂中包含这个模块 −

Now, you can include this module in a class as follows −

#!/usr/bin/ruby
$LOAD_PATH << '.'
require "support"

class Decade
include Week
   no_of_yrs = 10
   def no_of_months
      puts Week::FIRST_DAY
      number = 10*12
      puts number
   end
end
d1 = Decade.new
puts Week::FIRST_DAY
Week.weeks_in_month
Week.weeks_in_year
d1.no_of_months

这会产生以下结果 −

This will produce the following result −

Sunday
You have four weeks in a month
You have 52 weeks in a year
Sunday
120

Mixins in Ruby

在通读本节之前,我们假定您了解面向对象的概念。

Before going through this section, we assume you have the knowledge of Object Oriented Concepts.

当一个类可以从多个父类中继承特征时,该类应当展示多重继承。

When a class can inherit features from more than one parent class, the class is supposed to show multiple inheritance.

Ruby 不直接支持多重继承,但 Ruby 模块还有另一个美妙之处。总的来说,它们极大地消除了对多重继承的需求,提供了被称为混合的功能。

Ruby does not support multiple inheritance directly but Ruby Modules have another wonderful use. At a stroke, they pretty much eliminate the need for multiple inheritance, providing a facility called a mixin.

混合为您提供了一种受控良好的方式来对类添加功能。但是,当混合中的代码开始与使用它的类中的代码进行交互时,它们的真正威力才会显现出来。

Mixins give you a wonderfully controlled way of adding functionality to classes. However, their true power comes out when the code in the mixin starts to interact with code in the class that uses it.

让我们研究以下示例代码来了解混合 −

Let us examine the following sample code to gain an understand of mixin −

module A
   def a1
   end
   def a2
   end
end
module B
   def b1
   end
   def b2
   end
end

class Sample
include A
include B
   def s1
   end
end

samp = Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1

模块 A 包含方法 a1 和 a2。模块 B 包含方法 b1 和 b2。类 Sample 包含模块 A 和 B。类 Sample 可以访问所有四个方法,即 a1、a2、b1 和 b2。因此,您可以看到,类 Sample 从两个模块均继承。因此,您可以说类 Sample 展示了多重继承或混合。

Module A consists of the methods a1 and a2. Module B consists of the methods b1 and b2. The class Sample includes both modules A and B. The class Sample can access all four methods, namely, a1, a2, b1, and b2. Therefore, you can see that the class Sample inherits from both the modules. Thus, you can say the class Sample shows multiple inheritance or a mixin.