国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

directory search
Ruby用戶指南 3、開始 4、簡單的例子 5、字符串 6、正則表達式 7、數(shù)組 8、回到那些簡單的例子 9、流程控制 10、迭代器 11、面向對象思維 12、方法 13、類 14、繼承 15、重載方法 16、訪問控制 17、單態(tài)方法 18、模塊 19、過程對象 20、變量 21、全局變量 22、實變量 23、局部變量 24、類常量 25、異常處理:rescue 26、異常處理:ensure 27、存取器 28、對象的初始化 29、雜項 RGSS入門教程 1、什么是RGSS 2、開始:最簡單的腳本 3、數(shù)據(jù)類型:數(shù)字 4、數(shù)據(jù)類型:常量與變量 5、數(shù)據(jù)類型:字符串 6、控制語句:條件分歧語句 7、控制語句:循環(huán) 8、函數(shù) 9、對象與類 10、顯示圖片 11、數(shù)組 12、哈希表(關聯(lián)數(shù)組) 13、類 14、數(shù)據(jù)庫 15、游戲對象 16、精靈的管理 17、窗口的管理 18、活動指令 19、場景類 Programming Ruby的翻譯 Programming Ruby: The Pragmatic Programmer's Guide 前言 Roadmap Ruby.new 類,對象和變量 容器Containers,塊Blocks和迭代Iterators 標準類型 深入方法 表達式Expressions 異常,捕捉和拋出(已經開始,by jellen) 模塊 基本輸入輸出 線程和進程 當遭遇挫折 Ruby和它的世界 Ruby和Web開發(fā) Ruby Tk Ruby 和微軟的 Windows 擴展Ruby Ruby語言 (by jellen) 類和對象 (by jellen) Ruby安全 反射Reflection 內建類和方法 標準庫 OO設計 網絡和Web庫 Windows支持 內嵌文檔 交互式Ruby Shell 支持 Ruby參考手冊 Ruby首頁 卷首語 Ruby的啟動 環(huán)境變量 對象 執(zhí)行 結束時的相關處理 線程 安全模型 正則表達式 字句構造 程序 變量和常數(shù) 字面值 操作符表達式 控制結構 方法調用 類/方法的定義 內部函數(shù) 內部變量 內部常數(shù) 內部類/模塊/異常類 附加庫 Ruby變更記錄 ruby 1.6 特性 ruby 1.7 特性 Ruby術語集 Ruby的運行平臺 pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
characters

模塊 Modules



模塊是一種集中方法,類和常量的方法,主要帶來兩個好處:
  1. 模塊提供了一個命名空間(namespace )防止命名沖突。
  2. 通過模塊能實現(xiàn)混合插入(mixin)功能。

命名空間

當你寫的Ruby程序越來越大,越來越多之后,都會發(fā)現(xiàn)有很多代碼都可以重用,通常可以將相關例程組成一個庫,分布到不同的文件以便被其它Ruby程序共享。

通常,這些代碼都以類的形式組織在一起,所以你可能將一個類或者和其相關的幾個類放到一個文件中。

但是,有時候你也許需要把一些不能在常理上認為屬于一個類的東西組合到一起。

最初的辦法可能是將所有這些東西都放到一個文件中,然后在需要使用它的程序中引入這個文件,就像C語言那樣。但是,這樣做有一個問題,比如你編寫了一系列的三角函數(shù)sin,cos等,你將它們放到一個文件中,比如trig.rb,同時,Sally也做著類似的工作,創(chuàng)建了自己的庫文件action.rb,包括自己的一些例程,其中有beGood和sin方法。Joe想編寫一個程序,需要同時用到trig.rb和action.rb兩個文件,但是這兩個文件都定義了一個方法sin,這可不是什么好消息。

答案是模塊機制。模塊定義了一個命名空間,在這個空間里,你的方法和常量可以不必擔心和別人的重名,比如三角函數(shù)(trig)就可以放到一個模塊中:

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

然后Sally的方法可以放到另一個模塊:

 

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

模塊中常量的命名和類中的一樣,以大寫字母開頭。方法定義也類似,模塊的方法定義和類方法定義類似,格式為mod_name.method_name。

如果第三個程序需要使用這些模塊,只需要簡單的把這些模塊載入(使用Ruby的require語句,將在103頁討論),然后引用 限定的名字( qualified names)。

require?"trig"
require?"action"

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

和類方法一樣,調用一個模塊方法也以這個模塊名字為前綴然后一個點再加上方法名;引用一個模塊的則是在模塊后面加兩個冒號再加常量。

 

混合插入(Mixins)

模塊還有一個非常有用的作用,即通過模塊使用叫做混合插入(mixin)的機制實現(xiàn)了多重繼承。

在上一節(jié)的例子里,我們定義了模塊方法,方法名前面加上了模塊名作為前綴。如果這樣讓你想到這是類方法,那么你可能會進一步想“如果我在模塊里面定義實例變量會怎樣呢?”這個問題非常好,一個模塊不能產生實例,因為它不是類。但是,你可以在一個類的定義里包含(include )一個模塊,這時候,這個模塊中所有的實例方法都變成了在這個類所擁有(能使用)的方法了(all the module's instance methods are suddenly available as methods in the class as well)。這就叫做mixin,實際上,mix-in很像超類(superclasses)。

module?Debug
??def?whoAmI?
????"#{self.type.name}?(\##{self.id}):?#{self.to_s}"
??end
end
class?Phonograph
??include?Debug
??#?...
end
class?EightTrack
??include?Debug
??#?...
end
ph?=?Phonograph.new("West?End?Blues")
et?=?EightTrack.new("Surrealistic?Pillow")
ph.whoAmI? ? "Phonograph?(#537766170):?West?End?Blues"
et.whoAmI? ? "EightTrack?(#537765860):?Surrealistic?Pillow"

通過包含Debug模塊,PhonographEightTrack 都能訪問whoAmI?實例方法。

關于include語句需要注意幾點。首先,這個語句和文件無關,C程序員也使用預處理指令#include來將一個文件的內容在編譯的時候加入到另一個文件。而Ruby的include語句只是創(chuàng)建了一個指向一個有名字的模塊的引用,如果這個模塊在一個獨立的文件中,那么你必須先用require將這個文件引入,然后才能使用include。第二,Ruby的include不是簡單的將模塊的實例方法拷貝到類里面,而是建立一個從類到模塊的引用。如果很多個類都包含了同一個模塊,它們都指向同一樣東西。如果你修改了模塊中一個方法的定義,即使你的程序還在運行之中,你的類也能使用新的方法的行為[ 注意,我們這里說的是實例方法,實例變量永遠都是每個對象都有一份拷貝]

Mixin使得你能非常方便的給類增加方法,它的真正的強大之處在于能使模塊中的代碼和引入它的類中的代碼能相互作用。我們以標準的一個Ruby模塊Comparable 為例來說明,這個模塊可以用來給類增加比較操作符(<,<= ,==,>=,>等)和between?方法。為了使得它能工作,Comparable 假設使用它的類都定義了 <=>操作符,所以作為類的創(chuàng)建者,你定一個<=>方法,,引入Comparable模塊,然后,你就免費得到了6個其它的方法。在我們的Song類里,我們比較的基準是歌曲的時長。我們需要做的是增加<=>方法,和引入Comparable 模塊。

class?Song
??include?Comparable
??def?<=>(other)
????self.duration?<=>?other.duration
??end
end

然后,我們就可以檢查一下結果了,看看它的比較功能。

song1?=?Song.new("My?Way",??"Sinatra",?225)
song2?=?Song.new("Bicylops",?"Fleck",??260)
song1?<=>?song2 ? -1
song1??<??song2 ? true
song1?==??song1 ? true
song1??>??song2 ? false

最后,再看一下我們第43頁實現(xiàn)的Smalltalk的inject方法,我們可以把它改得更通用一些,通過使用一個能mixin的模塊。

module?Inject
??def?inject(n)
?????each?do?|value|
???????n?=?yield(n,?value)
?????end
?????n
??end
??def?sum(initial?=?0)
????inject(initial)?{?|n,?value|?n?+?value?}
??end
??def?product(initial?=?1)
????inject(initial)?{?|n,?value|?n?*?value?}
??end
end

然后,我們就可以用一些內建類來測試一下:

 

class?Array
??include?Inject
end
[?1,?2,?3,?4,?5?].sum ? 15
[?1,?2,?3,?4,?5?].product ? 120

class?Range
??include?Inject
end
(1..5).sum ? 15
(1..5).product ? 120
('a'..'m').sum("Letters:?") ? "Letters:?abcdefghijklm"

更多的關于mixin的例子,可以參看403頁開始的關于Enumerable 模塊的文檔。

 

Mixins中的實例變量(Instance Variables)

從C++轉到Ruby來的人經常問我們“在C++中,我們必須繞一些彎才能控制如何在多重繼承中共享實例變量,mixin中的實例變量會怎么樣呢?Ruby怎么處理這種情況呢?”

這對于初學者來說不是什么大問題,記住Ruby中的實例變量是如何工作的:以"@"作為前綴的變量作為當前對象self的實例變量。

對于混合插入來說,你要引入的模塊可以在你的類里創(chuàng)建實例變量,并且可以用attr和friends來定義這些變量的訪問器(accessor )。比如:

(For a mixin, this means that the module that you mix into your client class (the mixee?) may create instance variables in the client object and may use attr and friends to define accessors for these instance variables. )?

module?Notes
??attr??:concertA
??def?tuning(amt)
????@concertA?=?440.0?+?amt
??end
end

 
class?Trumpet  
??include?Notes  
??def?initialize(tune)  
????tuning(tune)  
????puts?"Instance?method?returns?#{concertA}"  
????puts?"Instance?variable?is?#{@concertA}"  
??end  
end
 
#?The?piano?is?a?little?flat,?so?we'll?match?it  
Trumpet.new(-5.3)
 
結果:
Instance?method?returns?434.7
Instance?variable?is?434.7

我們不僅訪問了模塊中的方法,我們也可以訪問它的實例變量。但是,這樣也會有一定的風險,比如不同的模塊可能定義了一個同名的實例變量,從而產生了沖突。

module?MajorScales
??def?majorNum
????@numNotes?=?7?if?@numNotes.nil?
????@numNotes?#?Return?7
??end
end

 
module?PentatonicScales   
??def?pentaNum   
????@numNotes?=?5?if?@numNotes.nil?   
????@numNotes?#?Return?5?   
??end   
end
 
class?ScaleDemo   
??include?MajorScales   
??include?PentatonicScales   
??def?initialize   
????puts?majorNum?#?Should?be?7   
????puts?pentaNum?#?Should?be?5   
??end   
end
 
ScaleDemo.new
  
結果:
7
7

上面的兩個模塊中都定義了實例變量@numNotes,當然程序最后的結果也與作者的期望的結果不同。

 

一般來說,mixin的模塊本身并不怎么攜帶實例數(shù)據(jù),它們使用訪問器(accessors )來從對象取得數(shù)據(jù)。但是如果你想要創(chuàng)建一個必須要有自己狀態(tài)的模塊,請確定這個模塊的實例變量的名字要唯一,不要和其它模塊的重名(比如用模塊名作為變量名的一部分)

迭代器和模塊 Enumerable?

你應該早就注意到了Ruby的集合類(collection classes)支持很多對它的處理:遍歷,排序等等,沒準你也會想要是自己的類支持這么多優(yōu)秀的特點就更好了。

當然,答案是肯定的,通過使用混合插入這個有用的機制和模塊Enumerable,你只需要再寫一個名為each的迭代方法就可以了,在這個方法里,依次返回你自己的集合類的元素。混合插入Enumerable模塊,然后你的類就支持了比如map,include?,find_all?等方法了。如果你的集合里的元素對象支持<=>方法,那么你的這個集合也可以得到min,max,sort方法。

?

包含(Including)其它文件

因為使用Ruby輕松的能編寫優(yōu)良的模塊化的代碼,你會經常發(fā)現(xiàn)自己會寫一些包含自包含的代碼,比如面向x的接口,用于y的算法等。一般的時候,我們會把這些文件作為類或者模塊的庫。

有了這些文件,如果你想把它們整合到你的新程序中,Ruby提供了兩種方法:

load?"filename.rb"

 
require?"filename"
  

load方法每次執(zhí)行都會包含一個Ruby源文件,而require只會包含一個文件一次,而且,require還有別的功能,它還能裝載共享二進制的庫文件( load shared binary libraries)。這兩個方法都接收相對和絕對的文件路徑作為參數(shù),如果給的是相對路徑(或者只是一個文件名),系統(tǒng)將會在當前的裝載路徑(load path)中的每個文件夾下尋找這個文件(裝載路徑保存在全局變量$:中,見140頁的討論)

使用load和require包含的文件也可以包含其它文件。其中需要注意的是require是一個可執(zhí)行的語句,它可以在一個if語句里使用,or it may include a string that was just built。包含時候的查找路徑也可以在運行時候更改,你可以將需要的目錄加到$:,這是一個數(shù)組。

因為load將無條件的裝載應該源文件,你可以用它在運行時候重新裝載一個可能在程序運行之后更改過的文件。

5.times?do?|i|
???File.open("temp.rb","w")?{?|f|
?????f.puts?"module?Temp\ndef?Temp.var()?#{i};?end\nend"
???}
???load?"temp.rb"
???puts?Temp.var
?end
結果:
0
1
2
3
4


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright ? 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).

Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.

Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
Previous article: Next article: