- Ruby 基礎
- Ruby - 首頁
- Ruby - 概述
- Ruby - 環境搭建
- Ruby - 語法
- Ruby - 類和物件
- Ruby - 變數
- Ruby - 運算子
- Ruby - 註釋
- Ruby - IF...ELSE
- Ruby - 迴圈
- Ruby - 方法
- Ruby - 塊
- Ruby - 模組
- Ruby - 字串
- Ruby - 陣列
- Ruby - 雜湊表
- Ruby - 日期和時間
- Ruby - 範圍
- Ruby - 迭代器
- Ruby - 檔案 I/O
- Ruby - 異常
Ruby - 面向物件
Ruby 是一種純面向物件的語言,在 Ruby 中,一切皆物件。Ruby 中的每個值都是物件,即使是最原始的東西:字串、數字,甚至是真假值。甚至類本身也是一個物件,它是 Class 類的例項。本章將帶您瞭解與面向物件 Ruby 相關的所有主要功能。
類用於指定物件的形態,它將資料表示和操作該資料的方法組合成一個簡潔的包。類中的資料和方法稱為類的成員。
Ruby 類定義
定義類時,您定義了資料型別的藍圖。這實際上並沒有定義任何資料,但它確實定義了類名的含義,即類的物件將包含什麼以及可以對這樣的物件執行哪些操作。
類定義以關鍵字 **class** 後跟 **類名** 開始,並以 **end** 結束。例如,我們使用關鍵字 class 定義了 Box 類,如下所示:
class Box code end
名稱必須以大寫字母開頭,按照慣例,包含多個單詞的名稱將連在一起,每個單詞的首字母大寫,並且沒有分隔符(駝峰命名法)。
定義 Ruby 物件
類為物件提供藍圖,因此基本上物件是從類建立的。我們使用 **new** 關鍵字宣告類的物件。以下語句聲明瞭兩個 Box 類的物件:
box1 = Box.new box2 = Box.new
initialize 方法
**initialize 方法** 是標準的 Ruby 類方法,其工作方式與其他面向物件程式語言中的 **建構函式** 幾乎相同。當您想要在建立物件時初始化一些類變數時,initialize 方法很有用。此方法可以接受引數列表,並且像任何其他 ruby 方法一樣,它前面都會加上 **def** 關鍵字,如下所示:
class Box
def initialize(w,h)
@width, @height = w, h
end
end
例項變數
**例項變數** 是一種類屬性,一旦使用類建立物件,它們就成為物件的屬性。每個物件的屬性都是單獨分配的,與其他物件不共享任何值。它們在類中使用 @ 運算子訪問,但要在類外部訪問它們,我們使用 **public** 方法,這些方法稱為 **訪問器方法**。如果我們採用上面定義的類 **Box**,則 @width 和 @height 是 Box 類的例項變數。
class Box
def initialize(w,h)
# assign instance variables
@width, @height = w, h
end
end
訪問器和設定器方法
為了使變數能夠從類外部訪問,必須在 **訪問器方法** 中定義它們,這些訪問器方法也稱為 getter 方法。下面的例子展示了訪問器方法的使用:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def printWidth
@width
end
def printHeight
@height
end
end
# create an object
box = Box.new(10, 20)
# use accessor methods
x = box.printWidth()
y = box.printHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
執行上述程式碼時,會產生以下結果:
Width of the box is : 10 Height of the box is : 20
與用於訪問變數值的訪問器方法類似,Ruby 提供了一種方法,可以使用 **設定器方法** 從類外部設定這些變數的值,定義如下:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def getWidth
@width
end
def getHeight
@height
end
# setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# create an object
box = Box.new(10, 20)
# use setter methods
box.setWidth = 30
box.setHeight = 50
# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
執行上述程式碼時,會產生以下結果:
Width of the box is : 30 Height of the box is : 50
例項方法
**例項方法** 也與我們使用 **def** 關鍵字定義任何其他方法的方式相同,並且只能使用類例項來使用它們,如下所示。它們的功能不限於訪問例項變數,還可以根據您的需求執行更多操作。
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
執行上述程式碼時,會產生以下結果:
Area of the box is : 200
類方法和變數
**類變數** 是一個變數,它在類的所有例項之間共享。換句話說,該變數只有一個例項,並且可以透過物件例項訪問它。類變數以兩個 @ 字元 (@@) 為字首。類變數必須在類定義中初始化,如下所示。
類方法使用 **def self.methodname()** 定義,它以 end 分隔符結尾,並將使用類名作為 **classname.methodname** 來呼叫,如以下示例所示:
#!/usr/bin/ruby -w
class Box
# Initialize our class variables
@@count = 0
def initialize(w,h)
# assign instance avriables
@width, @height = w, h
@@count += 1
end
def self.printCount()
puts "Box count is : #@@count"
end
end
# create two object
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)
# call class method to print box count
Box.printCount()
執行上述程式碼時,會產生以下結果:
Box count is : 2
to_s 方法
您定義的任何類都應該具有 **to_s** 例項方法以返回物件的字串表示形式。以下是一個簡單的示例,用於根據寬度和高度表示 Box 物件:
#!/usr/bin/ruby -w
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# define to_s method
def to_s
"(w:#@width,h:#@height)" # string formatting of the object.
end
end
# create an object
box = Box.new(10, 20)
# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"
執行上述程式碼時,會產生以下結果:
String representation of box is : (w:10,h:20)
訪問控制
Ruby 在例項方法級別提供了三個級別的保護,可以是 **public、private 或 protected**。Ruby 對例項變數和類變數不應用任何訪問控制。
**公共方法** - 公共方法可以被任何人呼叫。方法預設情況下是公共的,除了 initialize,它始終是私有的。
**私有方法** - 私有方法無法從類外部訪問,甚至無法檢視。只有類方法可以訪問私有成員。
**受保護的方法** - 受保護的方法只能由定義類及其子類的物件呼叫。訪問許可權保持在家族內部。
以下是一個簡單的示例,用於演示所有三種訪問修飾符的語法:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method by default it is public
def getArea
getWidth() * getHeight
end
# define private accessor methods
def getWidth
@width
end
def getHeight
@height
end
# make them private
private :getWidth, :getHeight
# instance method to print area
def printArea
@area = getWidth() * getHeight
puts "Big box area is : #@area"
end
# make it protected
protected :printArea
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
# try to call protected or methods
box.printArea()
執行上述程式碼時,會產生以下結果。這裡,第一個方法成功呼叫,但第二個方法出現了問題。
Area of the box is : 200 test.rb:42: protected method `printArea' called for # <Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)
類繼承
面向物件程式設計中最重要的概念之一是繼承。繼承允許我們根據另一個類來定義類,這使得建立和維護應用程式更加容易。
繼承還提供了重用程式碼功能和加快實現時間的機會,但不幸的是,Ruby 不支援多級繼承,但 Ruby 支援 **mixin**。mixin 類似於多重繼承的專門實現,其中只繼承介面部分。
建立類時,程式設計師可以指定新類應該繼承現有類的成員,而不是編寫全新的資料成員和成員函式。這個現有類稱為 **基類或超類**,新類稱為 **派生類或子類**。
Ruby 還支援子類化,即繼承,以下示例解釋了這個概念。擴充套件類的語法很簡單。只需將 < 字元和超類的名稱新增到您的類語句中即可。例如,以下將定義一個類 *BigBox* 作為 *Box* 的子類:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# define a subclass
class BigBox < Box
# add a new instance method
def printArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# create an object
box = BigBox.new(10, 20)
# print the area
box.printArea()
執行上述程式碼時,會產生以下結果:
Big box area is : 200
方法重寫
雖然您可以在派生類中新增新功能,但有時您可能想要更改父類中已定義方法的行為。您可以簡單地保持方法名稱相同並重寫方法的功能,如下面的示例所示:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# define a subclass
class BigBox < Box
# change existing getArea method as follows
def getArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# create an object
box = BigBox.new(10, 20)
# print the area using overriden method.
box.getArea()
運算子過載
我們希望 + 運算子使用 + 執行兩個 Box 物件的向量加法,* 運算子將 Box 的寬度和高度乘以標量,而一元 - 運算子則對 Box 的寬度和高度取反。這是一個具有定義的數學運算子的 Box 類的版本:
class Box
def initialize(w,h) # Initialize the width and height
@width,@height = w, h
end
def +(other) # Define + to do vector addition
Box.new(@width + other.width, @height + other.height)
end
def -@ # Define unary minus to negate width and height
Box.new(-@width, -@height)
end
def *(scalar) # To perform scalar multiplication
Box.new(@width*scalar, @height*scalar)
end
end
凍結物件
有時,我們希望防止物件被更改。Object 中的 freeze 方法允許我們做到這一點,有效地將物件轉換為常量。可以透過呼叫 **Object.freeze** 來凍結任何物件。凍結的物件可能不會被修改:您不能更改其例項變數。
您可以使用 **Object.frozen?** 方法檢查給定物件是否已凍結,如果物件已凍結,則返回 true,否則返回 false 值。以下示例闡明瞭這個概念:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def getWidth
@width
end
def getHeight
@height
end
# setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# create an object
box = Box.new(10, 20)
# let us freez this object
box.freeze
if( box.frozen? )
puts "Box object is frozen object"
else
puts "Box object is normal object"
end
# now try using setter methods
box.setWidth = 30
box.setHeight = 50
# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
執行上述程式碼時,會產生以下結果:
Box object is frozen object test.rb:20:in `setWidth=': can't modify frozen object (TypeError) from test.rb:39
類常量
您可以透過將直接數值或字串值賦值給變數來定義類中的常量,該變數是在不使用 @ 或 @@ 的情況下定義的。按照慣例,我們將常量名稱保留為大寫。
定義常量後,您無法更改其值,但您可以像變數一樣直接在類內訪問常量,但是如果您想在類外訪問常量,則必須使用 **classname::constant**,如下例所示。
#!/usr/bin/ruby -w
# define a class
class Box
BOX_COMPANY = "TATA Inc"
BOXWEIGHT = 10
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"
執行上述程式碼時,會產生以下結果:
Area of the box is : 200 TATA Inc Box weight is: 10
類常量是繼承的,並且可以像例項方法一樣被重寫。
使用 Allocate 建立物件
可能存在您想要在不呼叫其建構函式 **initialize**(即不使用 new 方法)的情況下建立物件的情況,在這種情況下,您可以呼叫 *allocate*,它將為您建立一個未初始化的物件,如下例所示:
#!/usr/bin/ruby -w
# define a class
class Box
attr_accessor :width, :height
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object using new
box1 = Box.new(10, 20)
# create another object using allocate
box2 = Box.allocate
# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"
# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"
執行上述程式碼時,會產生以下結果:
Area of the box is : 200 test.rb:14: warning: instance variable @width not initialized test.rb:14: warning: instance variable @height not initialized test.rb:14:in `getArea': undefined method `*' for nil:NilClass (NoMethodError) from test.rb:29
類資訊
如果類定義是可執行程式碼,這意味著它們在某個物件的上下文中執行:self 必須引用某些內容。讓我們找出它是什麼。
#!/usr/bin/ruby -w
class Box
# print class information
puts "Type of self = #{self.type}"
puts "Name of self = #{self.name}"
end
執行上述程式碼時,會產生以下結果:
Type of self = Class Name of self = Box
這意味著類定義是使用該類作為當前物件執行的。這意味著元類及其超類中的方法在方法定義的執行過程中將可用。