- 類
- 方法
- 代碼塊
- 類宏
- Eval方法
實例變量、方法、類
實例變量(Instance Variables)是當你使用它們時,才會被建立的對象。因此,即使是同一個類的實例,也可以有不同的實例變量。
從技術層面上來看,一個對象(實例)只是存儲了它的實例變量和其所屬類的引用。因此,一個對象的實例變量僅存在于對象中,方法(我們稱之為實例方法(Instance Methods))則存在于對象所屬的類中。這也就是為什么同一個類的實例都共享類中的方法,卻不能共享實例變量的原因了。
類
- 類也是對象。
- 因為類也是一個對象,能應用于對象的皆可運用于類。類和任何對象一樣,有它們自己的類,Class類即是Class類的實例。
- 與其它的對象一樣,類也有方法。對象的方法即是其所屬類的實例方法。亦即,任何一個類的方法就是Class類的實例方法。
- 所有的類有共同的祖先Object類(都是從Object類直接或間接繼承而來),而Object類又繼承自BasicObject類,Ruby類的根本。
- 類名是常量(Constant)。
n = Class.new
puts n.ancestors
puts n.supperclass
puts n.supperclass.supperclass
puts n.supperclass.supperclass.supperclass
打開類
其實這個就跟方法重定義是一樣的結果,不過隨意改動可能會產生嚴重的后果,比如說你改的這個方法在其它地方有使用到,所以這種方法還是慎用,除非你非常明確該方法不會造成其它后果。
puts 'abc'.replace('a') # a
class String
def replace(string)
puts '重新打開了類'
end
end
'abc'.replace('a') #'重新打開了類'
我們也可以使用細化
來實現這個過程
細化
module StringExtensions
refine String do
def replace(string)
puts '細化'
end
end
end
在需要使用這個方法的地方使用using
如:using StringExtensions
細化的好處就是不會全局影響,在你需要使用的地方using就可以了,風險相對較小。
調用方法
類中的方法是怎么調用的?
- 方法的查找(接收者和祖先鏈)
Ruby中要在類中查找一個方法,首先在它的類查找這個方法,如果沒有,則往上查找,如此類推,直到祖先鏈的頂端,到最后,如果還沒找到,會拋出method_missing異常。如果有了解過JS,那么你肯定非常明白這個過程,因為JS中的方法查找也是類似于這個過程。 - 執行方法
在執行方法的過程中,Ruby始終需要一個接收者的引用,也就是self
self關鍵字
任何時刻,Ruby中只有一個對象能充當當前對象,并且沒有哪個對象能長期充當這個角色,調用一個方法時,接收者就成為了self,從這一刻起,所有的實例變量都是self的實例變量,所有沒有明確指明接收者的方法都在self上調用。
舉個栗子:
class Book
def get_library
@book_count = 1000
self
end
def self.is_my_book?(book)
false
end
end
b = Book.new
b.get_library # 這個時候,b就充當了self
b.is_my_book?('Ruby元編程') # undefined method `is_book?' for #<Book:0x00000002b92268 @library=1000> (NoMethodError)
Book.is_my_book?('Ruby元編程') # false
上面調用is_my_book?的方法為什么會報錯?
那是因為 self.is_my_book?(book)
等于 Book.is_my_book?(book)
當b調用的時候,self引用b實例對象,不等于Book,所以就會拋出找不到方法的錯誤
方法
- 動態派發(調用方法:對象.send(方法名,參數))
class Book
def create_book
'Ruby元編程'
end
def update_book
'Ruby元編程'
end
def delete_book
'Ruby元編程'
end
def search_book
'Ruby元編程'
end
end
s = Book.new
puts s.send(:get_one_name)
puts s.send(:get_two_name)
puts s.send(:get_three_name)
puts s.send(:get_four_name)
- 動態定義
class Book
['create', 'update', 'delete', 'search'].each do |item|
define_method("#{item}_book"){
puts "#{item}-Ruby元編程"
}
end
end
b = Book.new
b.create_book # create-Ruby元編程
b.update_book # update-Ruby元編程
b.delete_book # delete-Ruby元編程
b.search_book # search-Ruby元編程
- method_missing(幽靈方法)
# encoding: utf-8
class Book
def method_missing(name, *argc)
if [:create_book, :update_book, :delete_book, :search_book].include?(name)
puts "#{name}-Ruby元編程"
else
super
end
end
end
b = Book.new
b.create_book# create-Ruby元編程
b.update_book# update-Ruby元編程
b.delete_book # delete-Ruby元編程
b.search_book# search-Ruby元編程
b.book # undefined method `book'
代碼塊
...
類宏
如果按照以前的做法,定義一個屬性的讀寫必須將每個屬性定義一個Get 和 Set方法,比如如下代碼
class Post
def title=(title)
@title = title
end
def title
@title
end
....
....
如果像一篇文章這樣,定義title,content,author等屬性,就需要寫3組這樣的方法,非常不方便。這個時候,就要亮出Ruby的類宏attr_accessor
(module的類里面的一個C語言寫的方法,附上超鏈接,以上代碼就可以寫成
class Post
attr_accessor :title
end