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

directory search
Ruby用戶指南 3、開始 4、簡單的例子 5、字符串 6、正則表達(dá)式 7、數(shù)組 8、回到那些簡單的例子 9、流程控制 10、迭代器 11、面向?qū)ο笏季S 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、哈希表(關(guān)聯(lián)數(shù)組) 13、類 14、數(shù)據(jù)庫 15、游戲?qū)ο?/a> 16、精靈的管理 17、窗口的管理 18、活動指令 19、場景類 Programming Ruby的翻譯 Programming Ruby: The Pragmatic Programmer's Guide 前言 Roadmap Ruby.new 類,對象和變量 容器Containers,塊Blocks和迭代Iterators 標(biāo)準(zhǔn)類型 深入方法 表達(dá)式Expressions 異常,捕捉和拋出(已經(jīng)開始,by jellen) 模塊 基本輸入輸出 線程和進(jìn)程 當(dāng)遭遇挫折 Ruby和它的世界 Ruby和Web開發(fā) Ruby Tk Ruby 和微軟的 Windows 擴(kuò)展Ruby Ruby語言 (by jellen) 類和對象 (by jellen) Ruby安全 反射Reflection 內(nèi)建類和方法 標(biāo)準(zhǔn)庫 OO設(shè)計 網(wǎng)絡(luò)和Web庫 Windows支持 內(nèi)嵌文檔 交互式Ruby Shell 支持 Ruby參考手冊 Ruby首頁 卷首語 Ruby的啟動 環(huán)境變量 對象 執(zhí)行 結(jié)束時的相關(guān)處理 線程 安全模型 正則表達(dá)式 字句構(gòu)造 程序 變量和常數(shù) 字面值 操作符表達(dá)式 控制結(jié)構(gòu) 方法調(diào)用 類/方法的定義 內(nèi)部函數(shù) 內(nèi)部變量 內(nèi)部常數(shù) 內(nèi)部類/模塊/異常類 附加庫 Ruby變更記錄 ruby 1.6 特性 ruby 1.7 特性 Ruby術(shù)語集 Ruby的運行平臺 pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
characters

容器,塊( Blocks)和迭代器( Iterator)



??? 一個自動點唱機(jī)只有一首歌恐怕不會太流行,所以我們需要建立一個歌曲目錄和一個等待播放的列表。這都是容器的例子,一個包含若干個對其它對象引用的對象。

??? 目錄和播放列表都有類似的操作,增加歌曲,刪除歌曲,返回歌曲列表等等。播放列表可能還需要別的方法,比如插入廣告,記錄累計播放時間等,我們將在后面考率這些問題?,F(xiàn)在,我們需要建立一個SongList類,以便在目錄和播放列表中使用。

容器

??? 在開始實現(xiàn)之前,我們要知道怎么在SongList中存儲歌曲列表。我們有三個明顯得選擇:Ruby的提供的Array,Ruby提供的Hash,或者我們自己創(chuàng)建一個列表結(jié)構(gòu)。下面我們來看看數(shù)組合和哈希,然后選擇一個來在我們的類中使用。

數(shù)組Arrays

數(shù)組類包含了若干個對其它對象的引用,每個引用在數(shù)組的一個位置上,用一個正整數(shù)來索引。

你可以直接指定一組值來創(chuàng)建一個數(shù)組,或者用數(shù)組類的new方法。用第一種方法創(chuàng)建數(shù)組要用中括號把各個元素括起來,每個元素之間用逗號隔開。

a?=?[?3.14159,?"pie",?99?]
a.type ? Array
a.length ? 3
a[0] ? 3.14159
a[1] ? "pie"
a[2] ? 99
a[3] ? nil
b?=?Array.new
b.type ? Array
b.length ? 0
b[0]?=?"second"
b[1]?=?"array"
b ? ["second",?"array"]

數(shù)組指定索引的下標(biāo)用[ ]操作符,這實際上也是一個方法,可以在子類中被重載。數(shù)組索引從0開始,從左向右技術(shù),如果指定的索引為負(fù)數(shù),則表示從右邊開始計數(shù)(這時候最右邊的索引下標(biāo)為-1,不是0)。

 

a?=?[?1,?3,?5,?7,?9?]
a[-1] ? 9
a[-2] ? 7
a[-99] ? nil

 

你也可以一對數(shù)字[start,?count]作為下標(biāo),這將返回一個數(shù)組,包含原數(shù)組中從start開始的count個元素。

a?=?[?1,?3,?5,?7,?9?]
a[1,?3] ? [3,?5,?7]
a[3,?1] ? [7]
a[-3,?2] ? [5,?7]

 

??? 最后,你也可以在數(shù)組下標(biāo)中使用Range作為索引。Range可參看下一章。Range的起始值之間如果是2個點號,則包括最后的結(jié)束值,如果是3個點號,則Range的值不包括最后的那個邊界值。

a?=?[?1,?3,?5,?7,?9?]
a[1..3] ? [3,?5,?7]
a[1...3] ? [3,?5]
a[3..3] ? [7]
a[-3..-1] ? [5,?7,?9]

[ ]方法有一個對應(yīng)的 []= 方法,這個方法是用來給指定的位置設(shè)置新的值,如果數(shù)組的下標(biāo)位置超過了數(shù)組的大小,那么指定的下標(biāo)將被設(shè)為指定的值,而中間沒有涉及到的位置為設(shè)為nil。如下面例子數(shù)組最大下標(biāo)為4,而對a[6]設(shè)置新值,a[5]則被設(shè)為nil。

a = [ 1, 3, 5, 7, 9 ] ? [1, 3, 5, 7, 9]
a[1] = 'bat' ? [1, "bat", 5, 7, 9]
a[-3] = 'cat' ? [1, "bat", "cat", 7, 9]
a[3] = [ 9, 8 ] ? [1, "bat", "cat", [9, 8], 9]
a[6] = 99 ? [1, "bat", "cat", [9, 8], 9, nil, 99]

如果在[]= 方法中下標(biāo)索引為兩個數(shù)字(一個開始位置,一個長度)或者一個Range,則對應(yīng)的一系列值將被重新設(shè)置。如果第二個參數(shù)即長度為0,則右邊的值將被插入當(dāng)前位置,沒有值會被刪除。如果[ ]=右邊的長度和左邊下標(biāo)中指定的長度不一樣,則原數(shù)組自動進(jìn)行調(diào)整。

a = [ 1, 3, 5, 7, 9 ] ? [1, 3, 5, 7, 9]
a[2, 2] = 'cat' ? [1, 3, "cat", 9]
a[2, 0] = 'dog' ? [1, 3, "dog", "cat", 9]
a[1, 1] = [ 9, 8, 7 ] ? [1, 9, 8, 7, "dog", "cat", 9]
a[0..3] = [] ? ["dog", "cat", 9]
a[5] = 99 ? ["dog", "cat", 9, nil, nil, 99]

數(shù)組有很多有用的方法,使用這些方法你能用數(shù)組實現(xiàn)隊列,堆棧,列表等各種數(shù)據(jù)結(jié)構(gòu)。

?

哈希Hashes

Hashes (sometimes known as associative arrays or dictionaries) are similar to arrays, in that they are indexed collectives of object references.

However, while you index arrays with integers, you can index a hash with objects of any type: strings, regular expressions, and so on. When you store a value in a hash, you actually supply two objects---the key and the value. You can subsequently retrieve the value by indexing the hash with the same key. The values in a hash can be any objects of any type. The example that follows uses hash literals: a list of key?=>?value pairs between braces.

h?=?{?'dog'?=>?'canine',?'cat'?=>?'feline',?'donkey'?=>?'asinine'?}
h.length ? 3
h['dog'] ? "canine"
h['cow']?=?'bovine'
h[12]????=?'dodecine'
h['cat']?=?99
h ? {"cow"=>"bovine",?"cat"=>99,?12=>"dodecine",?"donkey"=>"asinine",?"dog"=>"canine"}

Compared with arrays, hashes have one significant advantage: they can use any object as an index. However, they also have a significant disadvantage: their elements are not ordered, so you cannot easily use a hash as a stack or a queue.

You'll find that hashes are one of the most commonly used data structures in Ruby. A full list of the methods implemented by class Hash starts on page 317.

Implementing a SongList Container

After that little diversion into arrays and hashes, we're now ready to implement the jukebox's SongList. Let's invent a basic list of methods we need in our SongList. We'll want to add to it as we go along, but it will do for now.

append( aSong ) ? list
Append the given song to the list.
deleteFirst() ? aSong
Remove the first song from the list, returning that song.
deleteLast() ? aSong
Remove the last song from the list, returning that song.
[ anIndex } ? aSong
Return the song identified by anIndex, which may be an integer index or a song title.

This list gives us a clue to the implementation. The ability to append songs at the end, and remove them from both the front and end, suggests a dequeue---a double-ended queue---which we know we can implement using an Array. Similarly, the ability to return a song at an integer position in the list is supported by arrays.

However, there's also the need to be able to retrieve songs by title, which might suggest using a hash, with the title as a key and the song as a value. Could we use a hash? Well, possibly, but there are problems. First a hash is unordered, so we'd probably need to use an ancillary array to keep track of the list. A bigger problem is that a hash does not support multiple keys with the same value. That would be a problem for our playlist, where the same song might be queued up for playing multiple times. So, for now we'll stick with an array of songs, searching it for titles when needed. If this becomes a performance bottleneck, we can always add some kind of hash-based lookup later.

We'll start our class with a basic initialize method, which creates the Array we'll use to hold the songs and stores a reference to it in the instance variable @songs.

class?SongList
??def?initialize
????@songs?=?Array.new
??end
end

The SongList#append method adds the given song to the end of the @songs array. It also returns self, a reference to the current SongList object. This is a useful convention, as it lets us chain together multiple calls to append. We'll see an example of this later.

class?SongList
??def?append(aSong)
????@songs.push(aSong)
????self
??end
end

Then we'll add the deleteFirst and deleteLast methods, trivially implemented using Array#shift and Array#pop , respectively.

class?SongList
??def?deleteFirst
????@songs.shift
??end
??def?deleteLast
????@songs.pop
??end
end

At this point, a quick test might be in order. First, we'll append four songs to the list. Just to show off, we'll use the fact that append returns the SongList object to chain together these method calls.

list?=?SongList.new
list.
??append(Song.new('title1',?'artist1',?1)).
??append(Song.new('title2',?'artist2',?2)).
??append(Song.new('title3',?'artist3',?3)).
??append(Song.new('title4',?'artist4',?4))

Then we'll check that songs are taken from the start and end of the list correctly, and that nil is returned when the list becomes empty.

list.deleteFirst ? Song:?title1--artist1?(1)
list.deleteFirst ? Song:?title2--artist2?(2)
list.deleteLast ? Song:?title4--artist4?(4)
list.deleteLast ? Song:?title3--artist3?(3)
list.deleteLast ? nil

So far so good. Our next method is [], which accesses elements by index. If the index is a number (which we check using Object#kind_of? ), we just return the element at that position.

class?SongList
??def?[](key)
????if?key.kind_of?(Integer)
??????@songs[key]
????else
??????#?...
????end
??end
end

Again, testing this is pretty trivial.

list[0] ? Song:?title1--artist1?(1)
list[2] ? Song:?title3--artist3?(3)
list[9] ? nil

Now we need to add the facility that lets us look up a song by title. This is going to involve scanning through the songs in the list, checking the title of each. To do this, we first need to spend a couple of pages looking at one of Ruby's neatest features: iterators.

塊和迭代器Blocks and Iterators

下面,我們要在SongList中修改[ ] 方法,使它能接受一個字符串參數(shù),返回以此為標(biāo)題的歌曲的??雌饋砦覀兒苋菀卓梢詫崿F(xiàn):我們有一個包含了很多Song對象的對象的數(shù)組,我們只需循環(huán)遍歷整個數(shù)組,找到匹配的那個就可以了。

class?SongList
??def?[](key)
????if?key.kind_of?(Integer)
??????return?@songs[key]
????else
??????for?i?in?0...@songs.length
????????return?@songs[i]?if?key?==?@songs[i].name
??????end
????end
????return?nil
??end
end

這樣已經(jīng)可以工作了,而且看上去很符合常規(guī):用一個for循環(huán)來遍歷數(shù)組。

有沒有更自然的方法呢?

當(dāng)然有,我們可以用Array的find方法。

class?SongList
??def?[](key)
????if?key.kind_of?(Integer)
??????result?=?@songs[key]
????else
??????result?=?@songs.find?{?|aSong|?key?==?aSong.name?}
????end
????return?result
??end
end

我們可以用if修飾符來使代碼更簡短一些。

class?SongList
??def?[](key)
????return?@songs[key]?if?key.kind_of?(Integer)
????return?@songs.find?{?|aSong|?aSong.name?==?key?}
??end
end

方法find就是一個迭代器,這個方法重復(fù)不斷地執(zhí)行一個給定的block。塊和迭代器都是Ruby中比較有趣的特點。我們后面會進(jìn)一步來討論這些特點。

實現(xiàn)迭代器

一個Ruby迭代器就是一個簡單的能接收代碼塊的方法。第一眼看上去,Ruby中的block像C,Java,Perl中的一樣,但是實際上是有不同的。

首先,塊在源代碼中緊挨著方法調(diào)用,并且和這個方法的最后一個參數(shù)寫在同一行上。其次,這個塊不會立即被執(zhí)行,Ruby首先會記住這個塊出現(xiàn)的上下文(局部變量,當(dāng)前對象等),然后進(jìn)入方法,這里也是魔術(shù)開始的地方。

在方法里面,這個塊才會用yield來調(diào)用執(zhí)行,就像這個塊是方法本身一樣,每當(dāng)yield在方法中被執(zhí)行,這個塊就會被調(diào)用。當(dāng)這個塊執(zhí)行完退出后,控制將交給yield后面的語句(yield來自一個有20多年歷史的語言:CLU)。我們來看一個小例子。

def?threeTimes
??yield
??yield
??yield
end
threeTimes?{?puts?"Hello"?}
produces:
Hello
Hello
Hello

這個塊(用兩個大括號定義)賦給了一個方法threeTimes,在這個方法里面,yield執(zhí)行了3次,每次執(zhí)行它都會調(diào)用給定的block,即打印一個歡迎語句。使塊變得有趣的是你可以給塊傳遞參數(shù),并且從塊中得到結(jié)果。下面例子,我們將會得到小于一個指定值得Fibonacci 數(shù)列。

def?fibUpTo(max)
??i1,?i2?=?1,?1????????#?parallel?assignment
??while?i1?<=?max
????yield?i1
????i1,?i2?=?i2,?i1+i2
??end
end
fibUpTo(1000)?{?|f|?print?f,?"?"?}
produces:
1?1?2?3?5?8?13?21?34?55?89?144?233?377?610?987

在這個例子中,yield接收一個參數(shù),這個參數(shù)將會在執(zhí)行的時候傳遞給指定的塊。在塊的定義中,參數(shù)用兩個豎線括起來,放在最前面。在這個例子中f用來接收yield傳遞的參數(shù),所以,這個塊才能打印這個序列。一個塊可以接受任意個參數(shù)。如果一個塊的參數(shù)和yield中傳遞的參數(shù)個數(shù)不一樣,將會怎樣呢?很巧合,這和我們在并行賦值(parallel assignment)中談到的原則一樣(如果一個block只接收一個參數(shù),而yield提供的參數(shù)多于1個,那么這些參數(shù)將被轉(zhuǎn)化為一個數(shù)組。)

傳遞給一個塊的參數(shù)可以是存在地局部變量,如果是這樣的話,那么這個局部變量的新值(如果在塊中被修改了)在塊退出后將會保留,這可能會有一定的副作用,但是這樣做有一個性能方面的考率。

一個塊也可以返回一個結(jié)果給調(diào)用它的方法。這個塊中的最后一個表達(dá)式的值將會返回給方法,Array中的find方法就是這樣工作的。(find在Enumerable中定義,被插入到了類Array

class?Array
??def?find
????for?i?in?0...size
??????value?=?self[i]
??????return?value?if?yield(value)
????end
????return?nil
??end
end
[1,?3,?5,?7,?9].find?{|v|?v*v?>?30?} ? 7

這個用法中數(shù)組將連續(xù)的元素傳遞給指定的塊,如果這個塊返回true,則這個方法返回當(dāng)前對應(yīng)的元素值,如果沒有符合的值,則返回nil。這個方法顯示了迭代器的好處,Array類只作自己應(yīng)該做的,訪問數(shù)組元素,而應(yīng)用代碼只關(guān)注于特殊的需求。

Ruby中的集合對象中也包含其它一些常用迭代器,其中之二是each和collect。each可以認(rèn)為是最簡單的迭代器,它們都會對集合的每個元素來調(diào)用塊。

[?1,?3,?5?].each?{?|i|?puts?i?}
produces:
1
3
5

另一個是collect,它跟each類似,它將集合中的元素傳遞給一個塊,在塊中處理后返回一個包含處理結(jié)果的新數(shù)組。

["H",?"A",?"L"].collect?{?|x|?x.succ?} ? ["I",?"B",?"M"]

Ruby 和 C++ 、 Java的比較

這值得我們再花一些時間來比較一下Ruby,C++,JAVA中的迭代器。在Ruby中,迭代器是一個簡單的方法,每當(dāng)它產(chǎn)生一個新值,都會調(diào)用yield方法。使用迭代器只需要給這個迭代器傳遞一個塊,不需要像C++,Java中那樣創(chuàng)建輔助類來處理迭代器的狀態(tài)。從這一點和其它一些特點來說,Ruby是一種透明語言,當(dāng)你寫程序的時候,你只需關(guān)注于讓功能能夠?qū)崿F(xiàn),而不必編寫腳手架來支持語言的一些功能。

迭代器不僅僅用在數(shù)組和哈希等集合結(jié)構(gòu)上,它也能返回上面Fibonacci 例子中那樣的序列值,Ruby中的輸入輸出類也用到了迭代器,這些類實現(xiàn)了迭代器接口,每次返回一個I/O流的下一行。

f?=?File.open("testfile")
f.each?do?|line|
??print?line
end
f.close
produces:
This?is?line?one
This?is?line?two
This?is?line?three
And?so?on...

讓我們再看看另外一個迭代器實現(xiàn)。Smalltalk也支持迭代器,如果你用smalltalk語言來計算一個數(shù)組中元素的和,可以這樣:

sumOfValues??????????????"Smalltalk?method"
????^self?values
??????????inject:?0
??????????into:?[?:sum?:element?|?sum?+?element?value]

inject 這樣工作:第一次指定的block被執(zhí)行的時候,sum被設(shè)成inject的參數(shù)(本例為0),element被設(shè)為數(shù)組的第一個元素。以后block被執(zhí)行的時候,sum的值設(shè)為上次block執(zhí)行后返回的值。這樣,sum就可以記錄總數(shù)了最后的inject的值是block最后一次執(zhí)行后返回的值。

Ruby 沒有inject 方法,但我們可以很容易的寫一個,在這個例子中我們把它加入Array類。

class?Array
??def?inject(n)
?????each?{?|value|?n?=?yield(n,?value)?}
?????n
??end
??def?sum
????inject(0)?{?|n,?value|?n?+?value?}
??end
??def?product
????inject(1)?{?|n,?value|?n?*?value?}
??end
end
[?1,?2,?3,?4,?5?].sum ? 15
[?1,?2,?3,?4,?5?].product ? 120

盡管block經(jīng)常是用在迭代器中,但是,塊也有其它一些有用的用處。

在事務(wù)處理中使用塊

block也可以用作定義一塊代碼,這些代碼必須在一定的事務(wù)控制下運行。比如,你經(jīng)常會打開一個文件,對內(nèi)容作一些處理,然后需要確保文件在最后會被關(guān)閉。盡管我們可以用常規(guī)的方法實現(xiàn),但是,我們可以讓文件對象自己負(fù)責(zé)關(guān)閉它。一個簡單例子如下(忽略了錯誤處理等):

class?File
??def?File.openAndProcess(*args)
????f?=?File.open(*args)
????yield?f
????f.close()
??end
end


File.openAndProcess("testfile",?"r")?do?|aFile|  
??print?while?aFile.gets  
end
   
produces:
This?is?line?one
This?is?line?two
This?is?line?three
And?so?on...

這個小例子闡述了幾個技術(shù)點。方法openAndProcess 是一個類方法,這個方法可以獨立于任何File對象來單獨調(diào)用,即不需要生成類的實例。我們在這個方法的參數(shù)列表中使用了 *args,這表示所有調(diào)用時候的參數(shù)將作為數(shù)組傳遞到這個方法。而這個參數(shù)是傳遞給File.open方法的。

一旦這個文件被打開,openAndProcess 將調(diào)用yield,然后將打開的文件對象傳遞給這個block。當(dāng)block返回后,這個文件將被關(guān)閉。這種情況下,關(guān)閉文件的任務(wù)就從使用文件對象的用戶轉(zhuǎn)變?yōu)槲募旧砹恕?/p>

最后,這個例子用do..end來定義一個塊,這和用兩個打括號定義一個塊只是有優(yōu)先級別的區(qū)別,將在后面討論。

讓文件自己管理自己的生命周期十分有用,Ruby自帶的File類就提供了這樣的支持。如果File.open調(diào)用時指定了一個block,那么這個塊就會用傳遞過來文件對象作為參數(shù)執(zhí)行,然后,當(dāng)塊結(jié)束后,這個文件會被文件對象關(guān)閉。這很有趣,也就是說File.open方法有兩個版本,一個接受block,一個不接受block。當(dāng)沒有指定block調(diào)用這個方法的時候,這個方法只會返回一個打開的文件對象。方法Kernel::block_given?提供了實現(xiàn)這種功能的可能,如果調(diào)用的時候給了一個block,這個方法將返回true,這樣,你也可以實現(xiàn)自己open方法:

class?File
??def?File.myOpen(*args)
????aFile?=?File.new(*args)
????#?If?there's?a?block,?pass?in?the?file?and?close
????#?the?file?when?it?returns
????if?block_given?
??????yield?aFile
??????aFile.close
??????aFile?=?nil
????end
????return?aFile
??end
end

塊和閉包

讓我們再回來看看自動點唱機(jī),某些時候,我們需要處理點唱機(jī)和用戶的界面:很多按鈕,供用戶選擇歌曲和控制播放,我們需要給這些按鈕指定相應(yīng)的時間處理代碼,而Ruby中的block就很適合干這樣的事情。假設(shè)點唱機(jī)的設(shè)計者通過Ruby擴(kuò)展為我們提供了一個基本的按鈕類。

bStart?=?Button.new("Start")
bPause?=?Button.new("Pause")
#?...

當(dāng)用戶按下按鈕之后如何處理呢?Button類提供了一個buttonPressed方法,在按鈕按下時能被回調(diào)。所以最簡單的方法創(chuàng)建Button的子類,然后在每個子類中實現(xiàn)buttonPressed 方法。

class?StartButton?<?Button
??def?initialize
????super("Start")???????#?invoke?Button's?initialize
??end
??def?buttonPressed
????#?do?start?actions...
??end
end

bStart?=?StartButton.new

這樣做有兩個問題,首先這樣將產(chǎn)生大量子類,如果Button變化了,所有子類都需要維護(hù);第二,按鈕按下之后需要執(zhí)行的行為不應(yīng)該在按鈕上表示,這是點唱機(jī)的責(zé)任。我們可以用塊來消除這些問題

class?JukeboxButton?<?Button
??def?initialize(label,?&action)
????super(label)
????@action?=?action
??end
??def?buttonPressed
????@action.call(self)
??end
end

 
bStart?=?JukeboxButton.new("Start")?{?songList.start?}   
bPause?=?JukeboxButton.new("Pause")?{?songList.pause?}
 

上面代碼的關(guān)鍵點在JukeboxButton#initialize的第二個參數(shù),這個參數(shù)前面帶有一個&符號,在Ruby中代表這個參數(shù)是一個塊,這個塊將會被轉(zhuǎn)化為一個Proc對象,并關(guān)聯(lián)道相應(yīng)變量。在本例中我們把它賦給實例變量@action 。當(dāng)回調(diào)方法buttonPressed 執(zhí)行時,我們用方法Proc#call來調(diào)用相應(yīng)的block。

當(dāng)創(chuàng)建一個Proc對象之后我們得到的是什么呢?很有趣,我們得到的不僅是一串代碼。和這個block定義相關(guān)聯(lián)的上下文環(huán)境(范圍內(nèi)的):self值,定義它的方法,變量,常量等。Ruby中的一個有趣的地方就是即使block定義時候的變量已經(jīng)不在它的使用范圍內(nèi),這個變量還保留著,仍可以使用

我們來看一個例子,這個例子用了方法proc,這個方法把一個block變?yōu)榱艘粋€Proc對象。

def?nTimes(aThing)
??return?proc?{?|n|?aThing?*?n?}
end
p1?=?nTimes(23)
p1.call(3) ? 69
p1.call(4) ? 92
p2?=?nTimes("Hello?")
p2.call(3) ? "Hello?Hello?Hello?"

方法nTimes 返回一個Proc對象,這個對象引用了這個函數(shù)的參數(shù):aThing 。即使這個參數(shù)在塊被調(diào)用時已經(jīng)不在自己的作用域里了,這個塊還是可以訪問這個參數(shù)。(比如p1.call(4),這個時候,雖然對p1的賦值語句中的參數(shù)23已經(jīng)超出了作用域范圍,但是它仍然保存著23×4=92。)


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: