## 17.模塊和混入
每當你想到模塊時,便會想到一個盒子或其他東西。 只需看看你的打印機即可。 它是一個模塊。 它可以做一些事情。 它有事要做。 以類似的方式,Ruby 中的模塊可以包含 Ruby 代碼來執行某些操作。 模塊是將 Ruby 代碼打包到可能的邏輯單元中的方法。 每當你想在模塊中使用代碼時,只需將其包含在 Ruby 程序中即可。
讓我們看一下第一個名為 [module_function.rb](code/module_function.rb) 的模塊程序。 以下程序具有兩個模塊,即`Star`和`Dollar`。 這兩個模塊具有稱為`line`的相同功能。 請注意,在模塊`Star`中的函數`line`中,我們打印一行 20 個星號(*)字符。 在模塊`Dollar`中的功能`line`中,我們以類似的方式打印了一行 20 美元($)的字符。 在文本編輯器中鍵入程序并執行。
```rb
# module_function.rb
module Star
def line
puts '*' * 20
end
end
module Dollar
def line
puts '$' * 20
end
end
include Star
line
include Dollar
line
```
輸出量
```rb
********************
$$$$$$$$$$$$$$$$$$$$
```
讓我們看一下模塊外部的程序。 我們有以下代碼:
```rb
include Star
line
include Dollar
line
```
在`include Star`行中,我們包含了`Star`模塊中的代碼,然后我們調用了函數`line`,因此輸出結果是一行 20 星。 看下一行,我們包含模塊`Dollar`。 `Dollar`也具有稱為`line`的功能。 由于此模塊是在`Star`之后調用的,因此 Dollar 模塊中的`line`函數會被重寫或正確地隱藏`Star`模塊中的`line`函數。 因此,在`include Dollar`之后調用`line`將在`Dollar`模塊的`line`功能中執行代碼。 因此,我們得到一行二十美元的符號。
在下面的示例 [module_function_0.rb](code/module_function_0.rb) 中,我們將看到調用`line`函數而不包含任何模塊時發生的情況。 在下面輸入程序并執行
```rb
# module_function_0.rb
module Star
def line
puts '*' * 20
end
end
module Dollar
def line
puts '$' * 20
end
end
line
```
Output
```rb
module_function_0.rb:15:in `<main>': undefined local variable or method `line' for main:Object (NameError)
```
如你所見,`line`被視為未定義的局部變量或方法 <sup class="footnote">[ [39](#_footnotedef_39 "View footnote.") ]</sup> 。 因此,可以說只有當模塊包含在程序中時,才能訪問模塊中的功能。
可以說,我們編寫了另一個模塊,該模塊不帶任何功能,而只是其中的代碼。 我寫了以下程序 linclude:code / module.rb [module.rb]只是因為我想看看會發生什么。 事實證明,當模塊在 Ruby 文件中編碼并執行時,默認情況下將執行模塊中的代碼。 即使我們不包含該模塊,也會發生這種情況。
```rb
# module.rb
module Something
puts "Something"
end
module Nothing
puts "Nothing"
end
```
Output
```rb
Something
Nothing
```
上面程序 [module.rb](code/module.rb) 的輸出打印出`Something`和`Nothing`。 我們放置了兩個名為`Something`的模塊,其中包含代碼`puts “Something”`,另一個包含了`Nothing`的模塊,其中包含`puts “Nothing”`。 盡管我沒有使用`include`語句將這些模塊包含在程序中,但無論如何它們下的代碼仍會執行。
### 17.1。 不包含的調用函數
在程序 [module_function.rb](code/module_function.rb) 中,我們已經看到了如何包含模塊并在其中調用函數。 我們印了一行星星和美元。 讓我們以不同的方式做同樣的事情。 這次,我們將不再使用 include 關鍵字。
鍵入程序 [module_function_1.rb](code/module_function_1.rb) 并執行它。
```rb
# module_function_1.rb
module Star
def Star.line
puts '*' * 20
end
end
module Dollar
def Dollar.line
puts '$' * 20
end
end
Dollar::line
Star::line
Dollar::line
```
Output
```rb
$$$$$$$$$$$$$$$$$$$$
********************
$$$$$$$$$$$$$$$$$$$$
```
看下面的代碼:
```rb
Dollar::line
Star::line
Dollar::line
```
當我們調用`Dollar::line`時,將執行`Dollar`模塊中的`line`函數。 當我們調用`Star::line`時,將執行`Star`模塊中的`line`函數。 因此,當你想在模塊中調用函數時,請使用以下語法`<module-name>::<function-name>`。
請注意,在模塊`Star`中,我們將功能線定義為`Star.line`,而不僅僅是`line`。 同樣,在模塊`Dollar`中,我們將其定義為`Dollar.line`。
好,我們開始了解模塊,現在讓我們開始動手。 鍵入下面的代碼( [module_function_2.rb](code/module_function_2.rb) )并執行它。
```rb
# module_function_2.rb
module Star
def Star.line
puts '*' * 20
end
end
module Dollar
def Dollar.line
puts '$' * 20
end
end
module At
def line
puts '@' * 20
end
end
include At
Dollar::line
Star::line
Dollar::line
line
```
Output
```rb
$$$$$$$$$$$$$$$$$$$$
********************
$$$$$$$$$$$$$$$$$$$$
@@@@@@@@@@@@@@@@@@@@
```
好的,你有一些輸出。 看一下以下幾行
```rb
include At
Dollar::line
Star::line
Dollar::line
line
```
請注意,我們首先使用`include At`語句包含了`At`模塊。 在執行`Dollar::line`語句時,我們得到了一行二十美元的輸出。 在執行`Star::line`時,我們得到 20 星的輸出。 接下來,我們再次調用`Dollar::line`,然后抓住問題。 我們只調用函數`line`。 由于我們首先包含了`At`,因此當遇到`line`語句時,它將調用`At`模塊中的 line 方法。 這表明盡管我們已經調用了`Dollar::line`和`Star::line`,但它并未在程序中包含 <sup class="footnote">[ [40](#_footnotedef_40 "View footnote.") ]</sup> 模塊代碼,而是僅執行了程序中的特定功能 模塊。
在 link:code / module_function _1.rb [module_function _1.rb]中,我們看到了如何在模塊中調用函數`Star::line`,其中`Star`是模塊名稱,`line`是函數名稱。 為此,我們在`Star`模塊中定義了`line`函數,如下所示
```rb
def Star.line
puts '*' * 20
end
```
我們將其命名為`Star.line`而不是僅將其命名為`line`。 請注意, [module_function_3.rb](code/module_function_3.rb) 與 [module_function_1.rb](code/module_function_1.rb) 相似,但對`Dollar`模塊中的`line`功能進行了深入研究。 它沒有命名為`Dollar.line`,而是命名為`Star.line`。 如果我們將這樣的代碼弄亂了怎么辦? 執行以下程序并查看。
```rb
# module_function_3.rb
module Star
def Star.line
puts '*' * 20
end
end
module Dollar
def Star.line
puts '$' * 20
end
end
module At
def line
puts '@' * 20
end
end
include At
Dollar::line
Star::line
Dollar::line
line
```
Output
```rb
@@@@@@@@@@@@@@@@@@@@
$$$$$$$$$$$$$$$$$$$$
@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@
```
注意,每當我們調用`Dollar::line`時,都會調用`At`模塊中的`line`函數。 這是因為由于我們在`Dollar`模塊中將其定義為`Star.line`,所以`Dollar::line`不存在,因此在`At`模塊中調用了功能`line`。 注意,我們已經使用語句 include `At`包含了`At`模塊。
現在我們考慮另一種情況,在`Dollar`模塊中(參見程序 [module_function_4.rb](code/module_function_4.rb) ),我們僅將函數`line`定義為`line`而不是`Dollar.line`。 在下面的程序中使用`Dollar::line`調用它時,我們看到`At`模塊中的`line`函數被調用。 因此,故事的寓意是,如果要在程序中調用`<module-name>::<function-name>`,請確保該函數在模塊內的名稱為`<module-name>.<function-name>`。
```rb
# module_function_4.rb
module Star
def Star.line
puts '*' * 20
end
end
module Dollar
def line
puts '$' * 20
end
end
module At
def line
puts '@' * 20
end
end
include At
Dollar::line
Star::line
Dollar::line
line
```
Output
```rb
@@@@@@@@@@@@@@@@@@@@
********************
@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@
```
### 17.2。 模塊中的類
我們已經了解了 Ruby 解釋器如何對模塊中的函數進行操作。 現在讓我們看一下它對模塊中類的行為。 在 [module_class.rb](code/module_class.rb) 下鍵入程序并執行。
```rb
# module_class.rb
module Instrument
class Ruler
def what_u_do?
puts "I take measurements"
end
end
end
module People
class Ruler
def what_u_do?
puts "I govern this land"
end
end
end
r1 = People::Ruler.new
r2 = Instrument::Ruler.new
r1.what_u_do?
r2.what_u_do?
```
Output
```rb
I govern this land
I take measurements
```
讓我們分析程序。 我們有兩個模塊。 第一個名為`Instrument`,第二個名為`People`。 兩者都有一個名為`Ruler`的類,并且兩個 Ruler 都有一個名為`what_u_do?`的方法。 很好,現在進入程序。 我們有一條語句`r1 = People::Ruler.new`,其中`r1`成為`People`模塊中`Ruler`類的實例變量。 同樣,我們具有`r2 = Instrument::Ruler.new`,其中`r2`成為`Instrument`模塊中`Ruler`類的實例變量。
可以通過執行以下代碼來驗證
```rb
r1.what_u_do?
r2.what_u_do?
```
其中調用`r1.what_u_do?``輸出`I govern this land`,調用`r2.what_u_do?`輸出`I take measurements`。
這個故事的寓意是,你可以在不同的模塊中使用相同的類名稱,只需使用`<module-name>::<class-name>`即可調用該類。 。
### 17.3。 混合蛋白
模塊的另一種用途是你可以根據需要在模塊中混合代碼。 這個叫做 mixin。 我們已經了解了 mixin,但我沒有告訴你這是 mixin。 例如,假設你正在用 Ruby for Linux 和 Apple 機器編寫某些應用程序。 你會發現某些代碼僅在 Linux 上有效,而其他代碼僅在 Apple 上有效,然后可以如下所示將它們分開。 Apple 組件進入 Apple 模塊,Linux 組件進入 Linux 模塊。
假設你的朋友使用 Linux 機器并想要運行你的程序。 你需要做的就是在代碼中包含 Linux,如下所示。
```rb
# mixin.rb
module Linux
# Code for linux goes here
def function
puts "This function contains code for Linux systems"
end
end
module Apple
# Code for apple goes here
def function
puts "This function contains code for Apple systems"
end
end
include Linux
function
```
Output
```rb
This function contains code for Linux systems
```
調用方法`function`時,將調用`Linux`模塊中的方法`function`。 簡而言之,你已經在程序中混入了 Linux 代碼,并保留了 Apple 的東西。
讓我們看看 mixin 的另一個例子。 看看下面的代碼 [mixin_2.rb](code/mixin_2.rb) 。 可以說你的客戶告訴他,他非常需要一個程序來計算圓的面積和球的體積。 因此,你開發了兩個名為`Circle`和`Sphere`的類,并配有代碼來查找面積和體積。 所以你的客戶很高興。 由于你的客戶位于銀河星系中,因此常數 Pi <sup class="footnote">[ [41](#_footnotedef_41 "View footnote.") ]</sup> 為 22 除以 7。因此,我們將`Pi`的值放在名為`Constants`的模塊中,然后 使用語句`include Constants`包含在`Circle`和`Sphere`類中。 在下面的程序中鍵入并執行它。
```rb
# mixin_2.rb
module Constants
Pi = 22.0/7
end
class Circle
include Constants
attr_accessor :radius
def area
Pi * radius * radius
end
end
class Sphere
include Constants
attr_accessor :radius
def volume
(4.0/3) * Pi * radius ** 3
end
end
c = Circle.new
c.radius = 7
s = Sphere.new
s.radius = 7
puts "Circle Area = #{c.area}"
puts "Sphere Volume = #{s.volume}"
```
Output
```rb
Circle Area = 154.0
Sphere Volume = 1437.333333333333
```
這樣你就可以得到一些輸出。 你可能會問,將常量放入模塊并使用`include`語句將其混合在類中有何好處? 上面的程序教你兩種道德
* 你可以將常量放入模塊中
* 如果你具有可以在類之間共享的通用代碼 <sup class="footnote">[ [42](#_footnotedef_42 "View footnote.") ]</sup> ,則可以將其放入模塊中并進行共享。
如果你在每個類中分別定義了`Pi`的值,并且你碰巧從仙女座星系中獲得了 Pi 為 57 除以 18.1364 的客戶端,則可以只在一個地方進行更改,即在`Constants`模塊和 看到更改反映在許多類中(在我們的例子中是`Circle`和`Sphere`類)。
因此,道德模塊有助于我們迎合超出我們銀河系的客戶,并且我們可以真正建立銀河帝國 <sup class="footnote">[ [43](#_footnotedef_43 "View footnote.") ]</sup> 。
- 前言
- 紅寶石
- 先決條件
- 1.安裝 Ruby
- 2.在線資源
- 3.入門
- 4.比較與邏輯
- 5.循環
- 6.數組
- 7.哈希和符號
- 8.范圍
- 9.功能
- 10.可變范圍
- 11.類&對象
- 12.安全導航
- 13.打破大型程序
- 14.結構和 OpenStruct
- 15. Rdoc
- 16. Ruby 樣式指南
- 17.模塊和混入
- 18.日期和時間
- 19.文件
- 20. Proc,Lambda 和塊
- 21.多線程
- 22.異常處理
- 23.正則表達式
- 24.寶石
- 25.元編程
- 26.基準
- 27.測試驅動開發
- 28.觀察者模式
- 29.模板模式
- 30.工廠模式
- 31.裝飾圖案
- 32.適配器模式
- 33.單例模式
- 34.復合模式
- 35.建造者模式
- 36.策略模式
- 贊助商
- 捐
- 人們怎么說
- 版權
- 取得這本書