前言
上一篇我們簡單介紹了下Ruby,這一節我們開始正式步入Ruby的世界,一探究竟。
Ruby特點
(1)面向對象支持。
(2)動態語言:我們可以修改已經定義過的類,也可以為現有類添加實例方法。
(3)可移植性好:不僅可以運行在UNIX操作系統上,還可以運行在Windows等操作系統上。
(4)弱類型語言:變量無需聲明,變量沒有類型,變量可以保存任何類型的數據。
(5)支持自動垃圾回收機制:避免我們手動進行垃圾回收。
(6)強大的異常處理機制:保證Ruby程序的健壯性。
(7)簡潔的語法:提供正則表達式支持,並支持運算符重載。
(8)清晰的命名規則。
(9)動態載入:運行時取決於所運行的操作系統。
(10)完全免費。
Ruby程序注釋
注釋有兩種形式:
(1)單行注釋。
(2)多行注釋。
Ruby使用井號(#)表示注釋的開始,跟在#號后面直到#號在這行結束的代碼將被解釋器忽略。如下:
#定義一個方法 def method puts "Hello World" end
以上為單行注釋。當然,我們有時需要為代碼文檔添加注釋,這時我們可以用單行注釋完成,此時文檔代碼注釋就需要我們通過rdoc命令來提取注釋。
Ruby命令規則
(1)以"$"開頭的變量為全局變量。
(2)以“@”開頭的變量為實例變量。
(3)以“@@”開頭的變量為類變量。
(4)以小寫字母或者下划線(_)開頭的變量為局部變量。
(5)以大寫字母開頭的變量為常量。
常量
雖然Ruby只要求常量的首字母大寫,但是為了提高可讀性,一般我們建議對Ruby中的常量全部大寫。
class Constant # 定義一個常量 Foo = 5 # 重新賦值 Foo = 6 puts Foo end
一般在其他編程語言中,對常量重新賦值,不會出錯,但是在Ruby中,雖然不會拋出錯誤,但是會給出警告信息: warning: already initialized constant Constant::Foo
(1)對常量不能重新賦值
那么問題來了,常量是否可以定義在任何地方呢?我們看看
def info FOO = 4 puts FOO end
此時會拋出錯誤: dynamic constant assignment (SyntaxError)
(2)常量只能在類、模塊里進行定義,絕不能在方法里定義。
Ruby變量及其作用域
局部變量
局部變量可以被定義在類內部、模塊內部或者方法內部,當我們以一個小寫字母開頭的變量進行賦值時,就表明了一個局部變量。改變量的作用域僅僅屬於該類、該模塊或者該方法,一旦離開該類、該模塊或方法,則此局部變量會自然消失。
# 定義一個類 class Apple # 定義類里局部變量 local = "屬於類的局部變量" puts local end # 定義一個方法 def info # 定義方法里的局部變量 local = "屬於方法的局部變量" puts local end # 調用方法 info # 定義一個模塊 module Vegetable # 定義模塊里的局部變量 local = "屬於模塊里的局部變量" puts local
上述分別在類、方法和模塊里面定義了三個局部變量相同的名字,但是三個局部變量互不干擾,它們僅僅在它們對應的類、方法和模塊內部有效。
【注意】我們可以定義一個頂層變量即未在上述類、方法以及模塊內部,此時此頂層變量就在頂層對象中也就類似於C#中的Object對象中,此時該變量的作用域范圍則是整個應用程序。
(1)局部變量不可在內部類和子類中訪問。如下:
class Fruit local = "Hello" class Apple puts local end end
此時會報錯: undefined local variable or method `local' for Fruit::Apple:Class (NameError)
那么問題來了:要是我們在頂層對象中定義一個頂層變量,那么在類中是否能訪問到呢?如下:
local = "Hello" class Apple puts local end
此時同樣也會報錯,我們上述已經講述,此頂層變量在頂層對象中,而此Apple則是頂層對象的子類,所以出現上述錯誤就解釋的通了。
那么問題又來了:聲明了局部變量后什么時候開始有效呢?我們來看看,測試便知:
class Apple puts local local = "Hello World" end
此時報錯如下: undefined local variable or method `local' for Apple:Class (NameError)
當我們在類、模塊和方法中聲明局部變量時,此時該局部變量就開始生效,隨着類、模塊和方法的定義結束而結束,但是我們必須在定義之后再使用此局部變量才有效。
(2) 局部變量必須先定義,然后才可使用。
全局變量
由於全局變量可以在任何地方進行訪問,所以通常我們應該盡量避免使用全局變量,因為全局變量會引起各個模塊之間的耦合。如下
$global = "Hello World" class Apple puts $global end def info puts $global end
我們定義了一個頂層的全局變量,該全局變量既可以在類中訪問也可以在方法中訪問。
(1)全局變量既可以在類中訪問也可以在方法中訪問。
那問題來了:全局變量是否必須和局部變量一樣,先定義然后才能使用呢?我們看看:
class Apple puts $global end
一運行什么都沒有也沒出錯,什么情況,我們再將代碼修改如下:
class Apple puts $global.nil? end
最后打印為 true ,所以我們得出結論。
(2)全局變量無需變量聲明,如果引用尚未初始化的全局變量,其值為nil。
實例變量
和靜態語言不同,Ruby語言是一門動態語言,因為Ruby的實例變量無需聲明,每個實例變量都會在第一次出現時動態加入對象。因此Ruby的實例變量通常在方法中定義類聲明,即該實例變量是屬於該方法所在類的實例,而不是該方法。我們來看看代碼這句話說得到底是什么意思,實踐出真知!
class Apple # 定義第一個方法 def info1 # 輸出實例變量@ puts @a end # 定義第二個方法 def info2 # 為實例變量賦值 @a = "Hello World" end end # 創建Apple類的實例 apple = Apple.new # 調用方法 apple.info2 apple.info1
即使我們在調用info1方法時此時實例變量@a並未定義,因為方法只有在真正調用時才生效,當我們調用info2方法時,此時會動態為Apple類添加一個@a的實例變量。
說明:在C#和Java中當創建對象時就會一次性為該對象的所有實例變量分配內存空間,但是Ruby卻不是這樣,因其動態性,在創建對象時該對象沒有任何實例變量,直到執行到為實例變量定義時,該對象才動態增加該實例變量。同時它類似於全局變量,實例變量無需顯示聲明即可使用,若使用一個未定義的實例變量則該實例變量的值為nil。但是實例變量與局部變量還有一點區別就是在於其生命周期,實例變量的生命周期與其對象的生命周期是相同的,只要該類的對象存在,則該對象的實例變量則將一直存在;而局部變量則是隨着方法的消亡而消亡(除非使用閉包)。
類變量
類變量從第一次開始賦值的地方開始生效,它既可以在類中定義,也可以在模塊中定義,還可以在方法中定義。如下在類中定義類變量代碼
class Apple # 在類中定義一個類變量 @@color = "紅色" # 直接訪問類變量 puts @@color def info # 在方法中訪問類變量 puts "蘋果的顏色是 "+@@color end end Apple.new.info
類變量和實例變量不同的是,類變量必須先定義,然后才能使用。若引用一個未定義的類變量,則會引發一個uninitialzed class varialbe。
同時我們也是可以在方法中定義類變量,如下:
class Apple def color= (att) # 定義類變量 @@color = att end def color # 訪問類變量 @@color end # 此處的@@color依然不可用 puts defined? @@color end #創建兩個Apple實例 a1 = Apple.new a2 = Apple.new #依次為兩個Apple的實例的@@color變量賦值 a1.color = "紅色" a2.color = "綠色" #調用a1的方法來訪問@@color變量 puts a1.color
上述打印出 綠色 ,當調用a1.color,此時@@color並未進行定義,此時@@color是為nil,然后將其類變量添加到該實例對象中,
那么問題來了:當調用a1.color = "紅色"時,因為此前a2.color = "綠色",此時結果怎么會變成了“綠色”了呢?
此時則會涉及到類變量的一個特性:一個類 、其子類以及它們的實例的同名類變量共享了同一快內存區域即一個類、其子類以及它們的 實例的同名類變量都引用了同一個類變量。
結語
類變量與常量的區別
(1)類變量可以重復賦值(但對常量賦值會發出警告)。
(2)類變量默認是protected的,不能在類外部直接引用(在繼承中可以引用或賦值)。
類變量與實例變量的區別
(1)在類范圍內定義的類變量,可以在該類的方法中訪問,但實例變量不行。
(2)類變量可在子類中引用或者賦值,但實例變量值可在類范圍內直接引用或賦值。