?
本文檔使用 PHP中文網(wǎng)手冊(cè) 發(fā)布
Ruby程序的執(zhí)行就是對(duì)代碼進(jìn)行計(jì)算的過程。先編譯程序文本,遇到BEGIN就對(duì)其作出計(jì)算;然后計(jì)算頂層的一系列的表達(dá)式;若遇到END的話,將在最后對(duì)其進(jìn)行處理然后結(jié)束程序(關(guān)于結(jié)束程序時(shí)處理步驟的詳細(xì)過程請(qǐng)參考結(jié)束程序時(shí)的相關(guān)處理)。
if句的計(jì)算過程如下:先對(duì)條件表達(dá)式進(jìn)行計(jì)算,若為真則執(zhí)行相應(yīng)代碼段,若為假則依次計(jì)算elseif部分的條件表達(dá)式,若遇到值為真的表達(dá)式則執(zhí)行相應(yīng)的代碼段。若所有的條件表達(dá)式的值都為假的話,就執(zhí)行else部分的代碼段。
語句的值取決于最后執(zhí)行的代碼塊的值。若最后的代碼塊中沒有表達(dá)式,或者所有條件表達(dá)式的值都是假而且沒有else部分的話,則語句的值為nil。
定義類的內(nèi)容。在執(zhí)行時(shí)(而并非編譯時(shí))進(jìn)行計(jì)算。
書寫樣式
class ClassName [< 超類表達(dá)式] 表達(dá)式 end
在對(duì)類定義句進(jìn)行計(jì)算時(shí),將先試圖生成類。若有超類表達(dá)式就加以計(jì)算,其值作為ClassName類的父類,然后生成ClassName類的實(shí)例.若沒有超類表達(dá)式,就把Object作為其父類.
另一方面,若有同名類的話,就先使用那個(gè)同名類。然后處理超類表達(dá)式,若新生成的超類(在equal?)有所不同的話,就再生成一個(gè)新的類。
得到類之后就將其代入常數(shù)“ClassName”中,由此決定類名。此時(shí),若同名的常數(shù)中被代入一個(gè)非Class的實(shí)例的話,就會(huì)引發(fā)異常TypeError。
最后生成新的框架(frame),向頂層塊的self以及class設(shè)定要進(jìn)行定義的類,然后在框架的基礎(chǔ)上對(duì)定義句中的表達(dá)式進(jìn)行計(jì)算。我們無法得到類定義句的值。
也就是說,在Ruby中我們可以多次“追加類定義”。
定義模塊的內(nèi)容。在執(zhí)行時(shí)(而并非編譯時(shí))進(jìn)行計(jì)算。
書寫樣式
module ModuleName 模塊內(nèi)容 end
對(duì)模塊定義句進(jìn)行計(jì)算時(shí),首先會(huì)生成新的無名模塊。但是,若已經(jīng)有了一個(gè)名為ModuleName的模塊的話,就使用該模塊。此時(shí)就變成“追加模塊的定義”了。
得到模塊后就將其代入常數(shù)ModuleName中。這個(gè)常數(shù)就成為模塊的名稱。此時(shí),若向同名常數(shù)代入非模塊的話就會(huì)引發(fā)異常TypeError。
最后生成新的框架(frame),向頂層塊的self以及class中設(shè)定模塊ModuleName,然后在框架的基礎(chǔ)上對(duì)定義句中的表達(dá)式進(jìn)行計(jì)算。模塊定義句的值就是模塊內(nèi)容的最后一個(gè)表達(dá)式的值。若模塊內(nèi)容中沒有可計(jì)算的表達(dá)式時(shí),其值為nil。
定義對(duì)象的特殊類。在執(zhí)行時(shí)(而并非編譯時(shí))進(jìn)行計(jì)算。
書寫樣式
class << EXPR 類的內(nèi)容 end
先計(jì)算想定義特殊類的對(duì)象的表達(dá)式EXPR。然后生成該對(duì)象的特殊類(若尚未生成的話)。最后生成新框架,向頂層塊的self和class中設(shè)定新生成的特殊類。在新框架的基礎(chǔ)上對(duì)定義句中的表達(dá)式進(jìn)行計(jì)算。
特殊類定義句的值取決于類的內(nèi)容中的最后一個(gè)表達(dá)式的值。若沒有可計(jì)算的表達(dá)式時(shí),其值為nil。
請(qǐng)注意,Fixnum Symbol的實(shí)例以及 true false nil 不能定義特殊類
定義方法的內(nèi)容。在執(zhí)行時(shí)(而并非編譯時(shí))進(jìn)行計(jì)算。
書寫樣式
def method_name(arg, argwithdefault=expr, *restarg, &block) 方法內(nèi)容 end
對(duì)其進(jìn)行計(jì)算時(shí),將向運(yùn)行塊的class中定義該方法。若class中已經(jīng)存在同名的方法的話,則拋棄舊方法,添加新方法。
方法定義句的值為nil。
向?qū)ο蟮奶厥忸愔卸x方法。在執(zhí)行時(shí)(而并非編譯時(shí))進(jìn)行計(jì)算。
書寫樣式
def expr.method_name(arg, argwithdefault=expr, *restarg, &block) 方法內(nèi)容 end
首先計(jì)算表達(dá)式expr。然后生成對(duì)象的特殊類(若尚未生成的話)。最后向特殊類中定義方法method_name。
特殊方法定義句的值為nil。
請(qǐng)注意,Fixnum Symbol的實(shí)例以及true false nil不能定義特殊方法。
編譯時(shí)會(huì)用到(執(zhí)行時(shí)首先計(jì)算)
編譯時(shí)會(huì)用到(執(zhí)行時(shí)最后計(jì)算)
首先計(jì)算被調(diào)(receiver)表達(dá)式,得到被調(diào)用對(duì)象。省略被調(diào)表達(dá)式時(shí),調(diào)用塊的self將成為被調(diào)。
接下來從左到右地對(duì)參數(shù)表達(dá)式進(jìn)行計(jì)算,檢索被調(diào)里面的方法。若檢索失敗則引發(fā)異常NameError,成功的話就執(zhí)行方法。
另外,執(zhí)行方法的時(shí)候還可以添加塊(block)。若向方法添加塊時(shí),只有當(dāng)運(yùn)行中的方法執(zhí)行yield時(shí)才會(huì)對(duì)塊進(jìn)行計(jì)算。若沒有執(zhí)行yield的話,塊將被忽視,不會(huì)執(zhí)行。
將塊傳給方法時(shí),該塊將會(huì)繼承調(diào)用方的塊的self和class。只有Module#module_eval/class_eval和Object#instance_eval這三個(gè)例外,如下所示。
self和class都是被調(diào)(receiver)
self是被調(diào),class是被調(diào)的特殊類
把Proc對(duì)象和Binding對(duì)象傳給eval的第二參數(shù)時(shí),將在生成時(shí)的塊的基礎(chǔ)上對(duì)字符串進(jìn)行計(jì)算。
當(dāng)框架上只有一個(gè)塊的情況下,才開始執(zhí)行方法。下面我們暫時(shí)把這個(gè)塊稱作頂層塊(top level block)。頂層塊的self是被調(diào),class尚未被定義。
首先,若有必選參數(shù)的話,就把得到值代入頂層塊的局部變量。
若存在可選參數(shù),且已被省略的話,則在頂層塊上對(duì)默認(rèn)值表達(dá)式進(jìn)行計(jì)算,然后將得到的默認(rèn)值代入頂層塊的局部變量。若可選參數(shù)沒被省略的話,就把得到的值代入頂層塊的局部變量。
若存在*args這樣的參數(shù)的話,則將剩下的所有參數(shù)以數(shù)組的形式代入局部變量。
另外,若存在塊參數(shù)blockvar的話,則將傳給方法的塊進(jìn)行Proc對(duì)象化,然后代入頂層塊的局部變量blockvar中。若沒向方法傳遞塊的話,就代入nil。
接下來對(duì)方法內(nèi)容進(jìn)行計(jì)算,先計(jì)算方法層(method level)的rescue以及else部分,最后計(jì)算ensure部分。
整個(gè)方法的值取決于傳遞給return的值。若沒有調(diào)用return的話,則取決于 方法內(nèi)容/rescue/else 中最后被計(jì)算的表達(dá)式的值。若三個(gè)都為空的話,值為nil。
若向方法傳遞一個(gè)塊的話,這個(gè)方法就叫做帶塊的方法。帶塊方法遇到y(tǒng)ield時(shí)會(huì)轉(zhuǎn)向塊。
可以使用塊參數(shù)。
break...若塊位于堆??蚣?stack frame)上的話,就跳到框架的塊的后面。break并結(jié)束帶塊方法,其值為nil。若塊不在堆??蚣苌希瑒t引發(fā)異常LocalJumpError。
next 跳到塊的終點(diǎn)
retry 這個(gè)就復(fù)雜了...
略
賦值是指讓變量或常數(shù)記住某個(gè)對(duì)象。從語法的角度來看,雖然[]=和屬性賦值的方法調(diào)用看起來很像是賦值,但卻并非這里談到的賦值。
我們可以反復(fù)地將各種對(duì)象賦值給變量。也可以將各種對(duì)象賦值給常數(shù),但卻只能賦值一次。也就是說,一旦將對(duì)象賦值給常數(shù),就不能再更改。但這并不意味著賦值給常數(shù)的對(duì)象本身不允許更改,請(qǐng)您注意這點(diǎn)。
暫無
我們可以讓變量或常數(shù)記住一個(gè)對(duì)象。這叫做“變量(常數(shù))的賦值”。
當(dāng)對(duì)變量或常數(shù)進(jìn)行計(jì)算時(shí),它就會(huì)返回記住的對(duì)象。這叫做“變量(常數(shù))的調(diào)用”。
下面我們就分別來看一看變量和常數(shù)的賦值與調(diào)用過程。
局部變量只屬于一個(gè)塊。塊是指與代碼的某個(gè)范圍相對(duì)應(yīng)的運(yùn)行時(shí)的結(jié)構(gòu),可以嵌套。具體說來,它伴隨帶塊的方法調(diào)用以及eval系方法的執(zhí)行而出現(xiàn)。我們只能在局部變量的所屬塊以及該塊的嵌套塊中對(duì)局部變量進(jìn)行賦值和引用。
同時(shí),塊被放在特定的“框架”上,并歸屬于該框架。因此,不能調(diào)用其他框架上的局部變量。所謂框架是指開始執(zhí)行下列語句時(shí)生成的運(yùn)行時(shí)的結(jié)構(gòu)。
生成框架時(shí)自動(dòng)搭載一個(gè)塊,因此可以在這些語句中使用局部變量。
編譯時(shí),寫入程序代碼的局部變量將賦值給框架中的尚未定義的局部變量。局部變量被賦值時(shí)所在的塊就是它的歸屬塊。由此可知,編譯時(shí)局部變量的定義過程已經(jīng)完成(請(qǐng)注意,eval系的方法在執(zhí)行過程中進(jìn)行編譯)。定義的變量的初始值為nil。
局部變量在定義和調(diào)用時(shí),先是在塊中從外到內(nèi)地進(jìn)行搜索。其結(jié)果就是,局部變量不能進(jìn)行嵌套和屏蔽(shadowing)。但是,當(dāng)若干的塊處于非主從關(guān)系時(shí),其內(nèi)部可以包含不同的局部變量。
調(diào)用未定義(即沒有在代碼中標(biāo)出)的局部變量時(shí),Ruby會(huì)試圖把它當(dāng)作對(duì)self的(無參數(shù)的)方法調(diào)用來處理。若搜索方法失敗則引發(fā)異常NameError。
再來看一下調(diào)用塊的執(zhí)行情況,塊也可以帶參數(shù),但常被看做是在將要執(zhí)行的塊上進(jìn)行的多重賦值.例如,下面代碼的塊在開始執(zhí)行時(shí)
some_iterator do |a,b| .... end
首先會(huì)進(jìn)行下列操作。
a, b = <some_iterator 被yield的值 >
實(shí)例變量屬于一個(gè)對(duì)象,在self代表的塊的范圍內(nèi)可以進(jìn)行賦值和調(diào)用。實(shí)例變量的賦值過程同時(shí)也就是該變量的定義過程,若調(diào)用未定義的實(shí)例變量則返回nil。
remove_instance_variable
類變量為一個(gè)特定的類、該類的子類以及該類的實(shí)例所擁有。在以這些對(duì)象為self的塊的范圍內(nèi),可對(duì)其進(jìn)行賦值和調(diào)用。最初的賦值過程也兼做定義。若調(diào)用一個(gè)未經(jīng)定義的類變量的話就會(huì)引發(fā)異常NameError。
類變量的繼承和“繼承中止”
在任何地方都可以對(duì)全局變量進(jìn)行賦值和調(diào)用。最初的賦值過程兼做變量的定義,若調(diào)用一個(gè)未經(jīng)定義的全局變量的話,就會(huì)返回nil。
可跟蹤(?)
常數(shù)屬于類/模塊。我們可以使用除method以外的方式對(duì)其進(jìn)行賦值。最初的賦值兼做定義。對(duì)常數(shù)賦值時(shí)所在的塊的class就是常數(shù)的歸屬類。有個(gè)非常特殊的例外,我們可以使用Module#const_set方法來定義常數(shù),同時(shí),還可以使用Module#remove_const來取消常數(shù)。
無法對(duì)已定義的常數(shù)進(jìn)行再定義或賦值。實(shí)際上,只使用警告還可以進(jìn)行賦值,但這只是一時(shí)的應(yīng)急措施,并不符合規(guī)范。所以要少寫這樣的程序。
可調(diào)用范圍因?qū)懛ú煌兴町悺?/p>
可調(diào)用范圍有:常數(shù)所屬的類、子類、嵌套類的框架內(nèi)的代碼
可在任何地方調(diào)用
另外,像"::Const"這種前置"::"的寫法,只有寫成"Object::Const"時(shí)才能進(jìn)行調(diào)用。
下面這些變量看起來好像是局部變量,但實(shí)際上是保留字,返回確定的值。不可賦值。
返回該塊的self。
返回NilClass的唯一的實(shí)例--nil。
返回TrueClass的唯一的實(shí)例--true。
返回FalseClass的唯一的實(shí)例--false。