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

directory search
Ruby用戶指南 3、開始 4、簡單的例子 5、字符串 6、正則表達式 7、數組 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、數據類型:數字 4、數據類型:常量與變量 5、數據類型:字符串 6、控制語句:條件分歧語句 7、控制語句:循環(huán) 8、函數 9、對象與類 10、顯示圖片 11、數組 12、哈希表(關聯(lián)數組) 13、類 14、數據庫 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í)行 結束時的相關處理 線程 安全模型 正則表達式 字句構造 程序 變量和常數 字面值 操作符表達式 控制結構 方法調用 類/方法的定義 內部函數 內部變量 內部常數 內部類/模塊/異常類 附加庫 Ruby變更記錄 ruby 1.6 特性 ruby 1.7 特性 Ruby術語集 Ruby的運行平臺 pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
characters

類,對象和變量



看了前面我們談論到的一些例子,你也許會懷疑ruby的面向對象特性是否屬實,這章我們將會詳細講述這方面的內容。我們將會探討在ruby中如何創(chuàng)建類和對象,并且討論ruby比其他面向對象語言的一些更強之處。同時,我們也會部分實現我們數億美元的產品:基于因特網的爵士和布魯斯自動點唱機。

經過幾個月的工作,我們負責的研究人員決定我們的點唱機學要歌曲(songs),所以我們要在ruby中建立一個song類來表示現實中的歌曲。我們知道歌曲都有一個名字,演唱者,時長等,所以,我們的song對象也應如此。

我們開始創(chuàng)建了一個類:Song,[前面我們已經知道類名以大寫字母開頭,而方法以小寫字母開頭] 它只含有一個方法:initialize.

class?Song
??def?initialize(name,?artist,?duration)
????@name?????=?name
????@artist???=?artist
????@duration?=?duration
??end
end

initialize 在Ruby中是一個特殊方當法,當你調用Song.new 來創(chuàng)建一個Song 對象的時候, Ruby先創(chuàng)建一個沒有初始化的對象,然后調用它的initialize 方法,把傳給new的參數再傳給 initialize 這個方法。這樣,我們就可以編寫代碼來設置對象的狀態(tài)了。

對于類Song來說,initialize 方法接收3個參數,這三個參數作用域跟方法里的局部變量一樣,所以他們的命名方式更具備變量一樣,以小寫字母開頭。

每個對象代表自己的歌曲,他們有不同的名字,演唱者和時長等,也就是我們要把這些東西當成對象里面的實例變量。在ruby中實例變量用@開頭,比如我們上面的例子,@name,@artist,@duration都是實例變量。

讓我們看看我們的成果如何:

aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.inspect }} "#<Song:0x401b4924?@duration=260,?@artist=\"Fleck\",?@name=\"Bicylops\">"

它已經可以工作了。默認的inspect方法可以發(fā)送給任何對象,并且能得到這個對象的id和它的實例變量。從上面的結果看到我們正確的設置了對象的各個狀態(tài)。

我們的經驗告訴我們,在開發(fā)過程中,我們要多次打印Song中的內容,等inspect的默認格式不能完全滿足我們的要求,幸運的是,Ruby有一個標準的消息to_s,當向一個對象發(fā)送這個消息時,將會返回一個字符串,比如對于song來說:

aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.to_s }} "#<Song:0x401b499c>"

這樣沒多少用處,甚至還不如inspect,只有對象id。但是我們可以重載這個to_s方法。同時,我們也會用一點時間來說說Ruby中如何定義一個類。

在Ruby中,類永遠不會關閉,你可以一直往里面加入方法,不光是你自己寫的類,系統(tǒng)內建的類也可以加入的。你需要做的是打開一個類的定義,然后就可以加入自己的方法了。

這對我們來說非常好。在本章以后的例子里,我們只需要添加新的方法,老的方法還繼續(xù)存在,這樣省得我們花費多余的時間去在每個例子里都重寫一遍。盡管我們現在寫的代碼比較分散,但最好還是把它們都寫到一個文件中去比較好。

我想已足夠詳細了,還是回到我們要添加的to_s方法吧。

class?Song
??def?to_s
????"Song:?#{@name}--#{@artist}?(#{@duration})"
??end
end
aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.to_s }} "Song:?Bicylops--Fleck?(260)"

非常好,我們進步了不少。但是你也許覺得被騙了,我們曾經說過Ruby中所有對象都支持to_s方法,但沒有說怎么支持,答案是繼承。ruby如何決定當一個對象接受一個消息后執(zhí)行哪個方法,在下一節(jié)我們將會看到。

繼承和消息

繼承使你能夠創(chuàng)建一個基于一個類的特殊化的類,比如,我們的自動點唱機里有song這個類,但是隨著市場的需求,我們需要增加對卡拉ok的支持??ɡ璷k也是歌曲的一種,只不過光有伴奏,沒有演唱音,但是他們需要歌詞這個屬性,當我們播放卡拉ok時,歌詞還要顯示出來。

比較好的辦法是定義一個類KaraokeSong,它就是一個song,但是有一個歌詞的屬性。

class?KaraokeSong?<?Song
??def?initialize(name,?artist,?duration,?lyrics)
????super(name,?artist,?duration)
????@lyrics?=?lyrics
??end
end

" <?Song" 告訴 ruby karaokeSong 這個類是Song的一個子類,Song是karaokeSong的父類。先不用管initialize這個方法,以后我們會談到。

我們可以創(chuàng)建KaraokeSong 對象看看它是否能工作(在最后的系統(tǒng)中,lyrics存在另外的對象里,這個對象有文本和時間信息。為了測試方便,我們這里只用了字符串。這也是無類型語言的優(yōu)點:我們在執(zhí)行代碼之前不需要對所有對象進行定義。

aSong?=?KaraokeSong.new("My?Way",?"Sinatra",?225,?"And?now,?the...")
aSong.to_s }} "Song:?My?Way--Sinatra?(225)"

這個類已經可以工作了,但是to_s沒有顯示歌詞信息。

這和ruby如何決定調用哪個方法的機制有關。當ruby看到這個 aSong.to_s方法調用,它并不需要知道去哪里找to_s這個方法,而是要在程序運行到此的時候再去調用這個函數。開始在aSong里面找,如果這個類里面定義了一個和發(fā)送給這個對象的消息一樣名稱的方法的話,就運行這個方法。否則,就會到這個類的父類去找,如果還沒找到,再到父類的父類去找。這樣一直找到祖先Object。如果找到最高層還沒有找到這個方法,一般會返回一個錯誤。[實際上,你可以攔截這個錯誤,你可以在運行時彌補這個錯誤,見 Object#method_missing ]

現在再回到我們的例子,我們向aSong發(fā)送了一個消息to_s,在karaokeSong這個類里,ruby找不到to_s這個方法,所以,再去karaokeSong的父類Song去找。在父類里發(fā)現了這個方法,所以就執(zhí)行這個方法,所以,它只打印了除了歌詞的信息。類Song一點都不知道lyrics的存在。

我們可以在這里實現這個方法來彌補這個不足,又很多方法可以實現這個方法,我們先來看一下一個不是很好的例子,從Song的to_s拷貝出來一些代碼,然后加上lyric信息。

class?KaraokeSong
??#?...
??def?to_s
????"KS:?#{@name}--#{@artist}?(#{@duration})?[#{@lyrics}]"
??end
end
aSong?=?KaraokeSong.new("My?Way",?"Sinatra",?225,?"And?now,?the...")
aSong.to_s }} "KS:?My?Way--Sinatra?(225)?[And?now,?the...]"

我們正確地顯示了@lyrics 這個實例變量,但是這樣做直接在子類里訪問了父類的實例變量,為什么這樣實現to_s方法不好呢?

這和好的編程風格有關(可以稱作decoupling
The answer has to do with good programming style (and something called ). By poking around in our parent's internal state, we're tying ourselves tightly to its implementation. Say we decided to change Song to store the duration in milliseconds. Suddenly, KaraokeSong would start reporting ridiculous values. The idea of a karaoke version of ``My Way'' that lasts for 3750 minutes is just too frightening to consider.

我們需要每個類只操作自己內部的狀態(tài),當KaraokeSong#to_s 被調用的時候,先在KaraokeSong#to_s調用父類的to_s方法,然后在加上lyric信息返回給調用者。這里需要ruby的關鍵字"super"。當你不帶參數調用super時,ruby向父類發(fā)送消息,調用父類的同名函數(即和子類同名的函數),傳遞給當前類方法的參數會默認的傳給父類。比如改寫后如下:

class?KaraokeSong?<?Song
??#?Format?ourselves?as?a?string?by?appending
??#?our?lyrics?to?our?parent's?#to_s?value.
??def?to_s
????super?+?"?[#{@lyrics}]"
??end
end
aSong?=?KaraokeSong.new("My?Way",?"Sinatra",?225,?"And?now,?the...")
aSong.to_s }} "Song:?My?Way--Sinatra?(225)?[And?now,?the...]"

我們顯示的聲明了KaraokeSong是Song的一個子類,但是并沒有說明Song的父類。如果定義一個類時沒有指定父類,默認為Object為它的父類。也就是說,所有的類的祖先都是Object類,而且Object的實例方法在子類中也是可以訪問的。比如to_s是ruby中大概35個實例方法之一,這些方法列表后面可以看到。

繼承和 Mixins

像c++這樣的面向對象語言都支持多重繼承,也就是說一個類可以有多個父類,從每個類繼承特性。盡管很有效,但它有時候很危險,有可能產生混亂。

其他一些語言,比如java,支持單繼承,一個類只能有一個父類,盡管清洗明了,容易實現,但是也有一些缺點,因為事實上一個事務同時具備很多種事務的特征。比如一個球,既是球形的東西,也是能彈跳的東西。

ruby采取了有趣而強大的折中辦法,你能輕松的實現單繼承和多繼承。一個ruby只能有一個直接父類,是單繼承語言,但是ruby類可以包含其他的mixin(mixin可以看作是一個部分類定義a partial class definition)中的一些功能,從而引入附加的功能,以這種方式實現了多重繼承,并且不會出現多繼承語言中的問題。

上面我們已經看到了類和方法,下面來看看對象,也就是類的實例。

對象和屬性

Song對象有一些內部屬性,比如名稱和演唱者,這些屬性都是私有的,其他對象都不能直接訪問。一般來說,這樣是不錯的設計,每個對象只負責自己的完整性,一致性。

但是,如果把對象裝飾的這么秘密將會使這些對象變得毫無作用,我們能創(chuàng)建它,但是我們不能修改它的屬性。所以,我們可以定義一些方法,通過這些方法,外部對象可以訪問,修改對象的屬性。這些從外面看起來表現叫做屬性(attributes)。

對于我們Song對象,我們可能需要訪問它的名字和演唱者,以便在播放的時候打印出來,還有它的時長(可以用類似進度條來顯示)。

class?Song
??def?name
????@name
??end
??def?artist
????@artist
??end
??def?duration
????@duration
??end
end
aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.artist }} "Fleck"
aSong.name }} "Bicylops"
aSong.duration }} 260

這里,我們定義了三個訪問方法,每個方法返回一個實例屬性。在實際中,這些操作很普遍,所以ruby提供了一個方便的方法:用attr_reader,它將為我們自動創(chuàng)建訪問方法。

class?Song
??attr_reader?:name,?:artist,?:duration
end
aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.artist }} "Fleck"
aSong.name }} "Bicylops"
aSong.duration }} 260

這個例子引入了一些新東西,比如 ":artist"可以當作一個表達式,返回一個指向artist的符號鏈接。也可以把":artist"當作是artist的名字。這個例子里,我們定義了三個訪問方法: name, artist, duration。而實例變量@name, @artist, @duration會自動創(chuàng)建。這樣定義訪問方法和我們上面寫的一樣。

可寫屬性

有時候需要在外部對對象的屬性進行修改。比如,一首歌的時長這個屬性可能開始的時候只是一個估算的值,當第一次播放的時候,我們知道了它的真正時長,并且要把它寫回到Song這個對象。

在c++或者java中,我們可以用setter方法。

class?JavaSong?{?????????????????????//?Java?code
??private?Duration?myDuration;
??public?void?setDuration(Duration?newDuration)?{
????myDuration?=?newDuration;
??}
}
s?=?new?Song(....)
s.setDuration(length)

在Ruby中,可以象其他變量一樣訪問屬性,比如上面我們調用了aSong.name ,所以我們也應該像變量一樣給屬性賦值。在ruby中,這樣做就行:

class?Song
??def?duration=(newDuration)
????@duration?=?newDuration
??end
end
aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.duration }} 260
aSong.duration?=?257???#?set?attribute?with?updated?value
aSong.duration }} 257

賦值語句"aSong.duration?=?257"調用了aSong中的方法duration= 參數為257 。實際上,一個方法名以=結尾,就像這個屬性出現左邊的賦值語句一樣。同樣,ruby也為創(chuàng)建可寫屬性提供了一個快捷方式

?

class?Song
??attr_writer?:duration
end
aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.duration?=?257

虛擬屬性

這些屬性訪問方法不是對一個對象的實例變量的包裝,比如,你需要得到以分鐘為單位的時長,而不是以秒為單位:

class?Song
??def?durationInMinutes
????@duration/60.0???#?force?floating?point
??end
??def?durationInMinutes=(value)
????@duration?=?(value*60).to_i
??end
end
aSong?=?Song.new("Bicylops",?"Fleck",?260)
aSong.durationInMinutes }} 4.333333333
aSong.durationInMinutes?=?4.2
aSong.duration }} 252

這里我們用屬性方法建立了一個虛擬的實例變量,對于外面來說durationInMinutes可以看作和其他一樣的屬性,但實際上,并沒有與之對應的實例變量。

這并不止是有趣而已,在Bertrand Meyer 的杰作《Object-Oriented Software Construction》?中,作者稱這叫做統(tǒng)一訪問原則(Uniform Access Principle)。通過把這些實例變量和他們計算之后的值隱藏起來,你就可以不用在自己的實現里來處理這些問題,而且,當需要改動的時候,你只需要改動一個文件,而不是很多文件。

類變量和類方法

到目前為止我們討論的都是實例變量和實例方法,這些變量術語每個不同的對象,用方法來操作,有時候,類也可能需要自己的狀態(tài),所以引入了類變量。

Class Variables

一個類變量被所有它的對象實例共享,也可以被下面要提到的類方法修改。在系統(tǒng)中,類變量只有一個拷貝。類變量名以兩個at 即"@@"開頭,比如"@@count"。不想全局變量和實例變量,類變量在使用之前必須被初始化。通常初始化只是類定一中的一條賦值語句。

比如,在我們的自動點唱機中,我們想記錄一個指定的歌曲播放過多少次,這個次數應該是一個song實例變量,每當這個Song被播放,這個變量都要加1。如果,我們還想計算所有歌曲總共播放了多少次,我們可以找到所有Song對象,然后累加他們的播放次數,或者用全局變量,相反,這里我們用了類變量。

class?Song
??@@plays?=?0
??def?initialize(name,?artist,?duration)
????@name?????=?name
????@artist???=?artist
????@duration?=?duration
????@plays????=?0
??end
??def?play
????@plays?+=?1
????@@plays?+=?1
????"This??song:?#@plays?plays.?Total?#@@plays?plays."
??end
end

為了調試方便, Song#play方法返回了一個字符串,顯示了這首歌播放過多少次,和所有歌曲的總的播放次數。

s1?=?Song.new("Song1",?"Artist1",?234)??#?test?songs..
s2?=?Song.new("Song2",?"Artist2",?345)
s1.play }} "This??song:?1?plays.?Total?1?plays."
s2.play }} "This??song:?1?plays.?Total?2?plays."
s1.play }} "This??song:?2?plays.?Total?3?plays."
s1.play }} "This??song:?3?plays.?Total?4?plays."

類變量屬于類和它的實例私有,如果你想在外面訪問它,需要編寫訪問方法,既可以是實例的訪問方法,也可以是下面我們要說到的類的訪問方法。

Class Methods

有時候,一個類需要提供一個不需要任何類實例就能使用的方法。我們已經見過一個這樣的方法了,new方法創(chuàng)建了一個Song對象,但是它不屬于Song類。

aSong?=?Song.new(....)

你將會發(fā)現類方法貫穿于ruby的庫文件之中。比如,File類的對象表示一個打開的文件,但是File也提供了幾個類方法,比如刪除文件,我們不需要打開文件,直接調用 File.delete ,提供要刪除的文件名就行了。

File.delete("doomedFile")

類方法和實例方法定義時候是不一樣的,類方法定義的時候要加上類名:

class?Example

??def?instMeth??????????????#?instance?method ??end

??def?Example.classMeth?????#?class?method ??end

end

我們的自動點唱機是要收錢的,按歌曲數量而不是時間來收,所以提供長的歌曲不如提供短的歌曲效益高。我們不希望在SongList中出現太長的歌曲,所以我們在SongList里面定一個類方法,判斷一首歌是否超過了規(guī)定的長度。這個長度存在一個常量里面(常量以大寫字母開頭),并且在類體里面初始化這個常量。

class?SongList
??MaxTime?=?5*60???????????#??5?minutes
??def?SongList.isTooLong(aSong)
????return?aSong.duration?>?MaxTime
??end
end
song1?=?Song.new("Bicylops",?"Fleck",?260)
SongList.isTooLong(song1) }} false
song2?=?Song.new("The?Calling",?"Santana",?468)
SongList.isTooLong(song2) }} true

單例(Singletons)和其他構造函數

有時候,你想改變缺省的對象的創(chuàng)建方式,比如,對于我們的點唱機系統(tǒng),我們又很多點唱機,遍布全國,我們想盡可能的使他容易維護,所以我們需要記錄點唱機發(fā)生的所有事情,比如一首歌被播放了,收錢了等,所以我們需要一個日志類。因為我們想把帶寬留給音樂數據,所以日志記錄在本機。我們想一個點唱機系統(tǒng)只有一個log類,并被系統(tǒng)中的所有類共有使用。

通過使用單例模式,要想使用這個log類,只有一種創(chuàng)建方法:Logger.create,并且確保系統(tǒng)中只有一個log的實例存在。

class?Logger
??private_class_method?:new
??@@logger?=?nil
??def?Logger.create
????@@logger?=?new?unless?@@logger
????@@logger
??end
end

我們把logger類的new方法設成了私有的,這樣就不能用Looger.new來創(chuàng)建logger對象了。我們提供了一個類方法 Logger.create ,用到了類變量 @@logger ,這是一個指向logger類實例的引用??梢钥吹?,如果實例已經創(chuàng)建了,這個方法直接返回已經創(chuàng)建的實例,不會再創(chuàng)建第二個。[這里的實現是非線程安全的,如果有多個線程來訪問這個函數,可能會出產生多個logger對象。我們可以用ruby提供的Singleton mixin來解決,而不必自己處理線程安全問題。]我們可以檢查一下這兩個方法的返回情況。

Logger.create.id }} 537766930
Logger.create.id }} 537766930

用類方法來包裝構造函數,也可以讓使用你的類的人感到輕松。比如我們的類Shape代表一個多邊形,構造函數接收邊數和周長:

class?Shape
??def?initialize(numSides,?perimeter)
????#?...
??end
end

但是,多年以后,使用方法變了,現在需要提供shape的名稱,邊數,和邊長而不是周長。而我們只需要加幾個類方法就行了:

class?Shape
??def?Shape.triangle(sideLength)
????Shape.new(3,?sideLength*3)
??end
??def?Shape.square(sideLength)
????Shape.new(4,?sideLength*4)
??end
end

類方法還有很多強大有趣的特性,但是目前我們還是要繼續(xù)我們現在的內容。

Access Control

我們設計一個類的接口的時候,一個重要的問題是,我們應該向外界暴露多少內部實現,外部能訪問我們的類有多少限制。如果過多的讓外部訪問內部的東西,可能增加了耦合,用戶越來越依賴我們的類的內部實現,而不是邏輯接口。因為我們要改變一個實例的狀態(tài)需要調用這個實例的相關方法,控制對實例的方法的訪問,就能避免對對象實例的狀態(tài)的直接修改。Ruby提供了三種保護層次:
  • Public methods 任何人都可以訪問,沒有訪問控制。方法默認都是public(initialize除外)。
  • Protected methods 可以在本類或者子類中調用。訪問控制在家族內。
  • Private methods 不能用顯示的接收者來調用。cannot be called with an explicit receiver. Because you cannot specify an object when using them, private methods can be called only in the defining class and by direct descendents within that same object.

"protected"和"private"兩者的區(qū)別非常微妙,在ruby中,兩者的關系和在其他語言中是不一樣的。如果一個方法是protected的,它可以在定義它的實例或者子類的實例來調用。如果一個方法是"private"的,只可以在這個方法所處的對象中被使用,不能直接調用另一個對象的private方法。甚至這個對象就是調用者本身。
Ruby和其他oo語言另一個重要的不同點在于,ruby動態(tài)確定訪問控制,在程序運行而不是靜止時,只有你運行到那一行,才會去判斷是否出錯。

指定訪問控制

在一個類或者模塊定義中設定方法的訪問控制層次: public, protected,private。有兩種定義方法。

如果不帶參數使用 public/protected/private,那么這后面的方法默認都是指定的值,比如一行寫了private,那么后面的方法默認都是private,除非指定了另外的訪問控制符。

class?MyClass

??????def?method1????#?default?is?'public' ????????#... ??????end

??protected??????????#?后面方法將是?'protected'

??????def?method2????#?will?be?'protected' ????????#... ??????end

??private????????????#?后面方法將是?'private'

??????def?method3????#?will?be?'private' ????????#... ??????end

??public?????????????#?subsequent?methods?will?be?'public'

??????def?method4????#?and?this?will?be?'public' ????????#... ??????end end

另一種方法,定義方法的時候不指定訪問控制符,而是將相關的方法列在對應的訪問控制后面,比如:

class?MyClass

??def?method1 ??end

??#?...?and?so?on

??public????:method1,?:method4 ??protected?:method2 ??private???:method3 end

initialize方法自動聲明為private型。

現在來看看一個例子。假如我們有一個記帳系統(tǒng),每一個借方(debit)對應一個貸方(credit),我們要求都必須遵守這個規(guī)則,所以我們把debit和credit的方法設成private,提供了一個外部接口來處理:

class?Accounts

??private

????def?debit(account,?amount) ??????account.balance?-=?amount ????end ????def?credit(account,?amount) ??????account.balance?+=?amount ????end

??public

????#... ????def?transferToSavings(amount) ??????debit(@checking,?amount) ??????credit(@savings,?amount) ????end ????#... end

Protected access is used when objects need to access the internal state of other objects of the same class. For example, we may want to allow the individual Account objects to compare their raw balances, but may want to hide those balances from the rest of the world (perhaps because we present them in a different form).

class?Account
??attr_reader?:balance???????#?accessor?method?'balance'

??protected?:balance?????????#?and?make?it?protected

??def?greaterBalanceThan(other) ????return?@balance?>?other.balance ??end end

Because the attribute balance is protected, it's available only within Account objects.

變量Variables

變量用來跟蹤一個對象的狀態(tài),是指向其他對象的一個引用 。

person?=?"Tim"
person.id }} 537771100
person.type }} String
person }} "Tim"

第一行,我們創(chuàng)建了一個新字符串對象"Tim",person是指向這個字符串對象的一個引用,下兩行的測試語句顯示了這個對象的類型和id,最后顯示了它的值。

但變量是對象嗎?

在ruby中,答案是否定的。一個變量只是指向一個對象的引用。這些對象可能正在某地,比如堆棧中,變量只是指向了這些對象。
我們再看看稍微負責的例子

person1?=?"Tim"
person2?=?person1
person1[0]?=?'J'
person1 }} "Jim"
person2 }} "Jim"

我們改變了person1的第一個字符,但是第二個也跟著改了。這是因為變量只是指向一個對象的引用,而不是對象本身。賦值語句person2?=?person1 沒有創(chuàng)建新的對象,只是person2拷貝了person1的引用而已。所以person1和person2都指向了同一個對象。

有時候賦值語句只是為對象建立了別名,而潛在的創(chuàng)建了新的變量指向同一個對象。這在我們的代碼中可能會引起問題,但并不像你想的那么容易出錯。我們可以用String的dup方法,這個方法會創(chuàng)建一個新的字符串對象,并且內容和消息接受者(方法執(zhí)行者)一樣。

person1?=?"Tim"
person2?=?person1.dup
person1[0]?=?"J"
person1 }} "Jim"
person2 }} "Tim"

如果你不想別人修改一個對象,也可以凍結(freezing)這個對象。如果你修改一個被凍結的對象,ruby會拋出一個TypeError異常。

person1?=?"Tim"
person2?=?person1
person1.freeze???????#?prevent?modifications?to?the?object
person2[0]?=?"J"
produces:
prog.rb:4:in?`=':?can't?modify?frozen?string?(TypeError)
	from?prog.rb: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: