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