- 類(lèi)
- 方法
- 代碼塊
- 類(lèi)宏
- Eval方法
實(shí)例變量、方法、類(lèi)
實(shí)例變量(Instance Variables)是當(dāng)你使用它們時(shí),才會(huì)被建立的對(duì)象。因此,即使是同一個(gè)類(lèi)的實(shí)例,也可以有不同的實(shí)例變量。
從技術(shù)層面上來(lái)看,一個(gè)對(duì)象(實(shí)例)只是存儲(chǔ)了它的實(shí)例變量和其所屬類(lèi)的引用。因此,一個(gè)對(duì)象的實(shí)例變量?jī)H存在于對(duì)象中,方法(我們稱(chēng)之為實(shí)例方法(Instance Methods))則存在于對(duì)象所屬的類(lèi)中。這也就是為什么同一個(gè)類(lèi)的實(shí)例都共享類(lèi)中的方法,卻不能共享實(shí)例變量的原因了。
類(lèi)
- 類(lèi)也是對(duì)象。
- 因?yàn)轭?lèi)也是一個(gè)對(duì)象,能應(yīng)用于對(duì)象的皆可運(yùn)用于類(lèi)。類(lèi)和任何對(duì)象一樣,有它們自己的類(lèi),Class類(lèi)即是Class類(lèi)的實(shí)例。
- 與其它的對(duì)象一樣,類(lèi)也有方法。對(duì)象的方法即是其所屬類(lèi)的實(shí)例方法。亦即,任何一個(gè)類(lèi)的方法就是Class類(lèi)的實(shí)例方法。
- 所有的類(lèi)有共同的祖先Object類(lèi)(都是從Object類(lèi)直接或間接繼承而來(lái)),而Object類(lèi)又繼承自BasicObject類(lèi),Ruby類(lèi)的根本。
- 類(lèi)名是常量(Constant)。
n = Class.new
puts n.ancestors
puts n.supperclass
puts n.supperclass.supperclass
puts n.supperclass.supperclass.supperclass
打開(kāi)類(lèi)
其實(shí)這個(gè)就跟方法重定義是一樣的結(jié)果,不過(guò)隨意改動(dòng)可能會(huì)產(chǎn)生嚴(yán)重的后果,比如說(shuō)你改的這個(gè)方法在其它地方有使用到,所以這種方法還是慎用,除非你非常明確該方法不會(huì)造成其它后果。
puts 'abc'.replace('a') # a
class String
def replace(string)
puts '重新打開(kāi)了類(lèi)'
end
end
'abc'.replace('a') #'重新打開(kāi)了類(lèi)'
我們也可以使用細(xì)化來(lái)實(shí)現(xiàn)這個(gè)過(guò)程
細(xì)化
module StringExtensions
refine String do
def replace(string)
puts '細(xì)化'
end
end
end
在需要使用這個(gè)方法的地方使用using
如:using StringExtensions
細(xì)化的好處就是不會(huì)全局影響,在你需要使用的地方using就可以了,風(fēng)險(xiǎn)相對(duì)較小。
調(diào)用方法
類(lèi)中的方法是怎么調(diào)用的?
- 方法的查找(接收者和祖先鏈)
Ruby中要在類(lèi)中查找一個(gè)方法,首先在它的類(lèi)查找這個(gè)方法,如果沒(méi)有,則往上查找,如此類(lèi)推,直到祖先鏈的頂端,到最后,如果還沒(méi)找到,會(huì)拋出method_missing異常。如果有了解過(guò)JS,那么你肯定非常明白這個(gè)過(guò)程,因?yàn)镴S中的方法查找也是類(lèi)似于這個(gè)過(guò)程。 - 執(zhí)行方法
在執(zhí)行方法的過(guò)程中,Ruby始終需要一個(gè)接收者的引用,也就是self
self關(guān)鍵字
任何時(shí)刻,Ruby中只有一個(gè)對(duì)象能充當(dāng)當(dāng)前對(duì)象,并且沒(méi)有哪個(gè)對(duì)象能長(zhǎng)期充當(dāng)這個(gè)角色,調(diào)用一個(gè)方法時(shí),接收者就成為了self,從這一刻起,所有的實(shí)例變量都是self的實(shí)例變量,所有沒(méi)有明確指明接收者的方法都在self上調(diào)用。
舉個(gè)栗子:
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 # 這個(gè)時(shí)候,b就充當(dāng)了self
b.is_my_book?('Ruby元編程') # undefined method `is_book?' for #<Book:0x00000002b92268 @library=1000> (NoMethodError)
Book.is_my_book?('Ruby元編程') # false
上面調(diào)用is_my_book?的方法為什么會(huì)報(bào)錯(cuò)?
那是因?yàn)?self.is_my_book?(book) 等于 Book.is_my_book?(book)
當(dāng)b調(diào)用的時(shí)候,self引用b實(shí)例對(duì)象,不等于Book,所以就會(huì)拋出找不到方法的錯(cuò)誤
方法
- 動(dòng)態(tài)派發(fā)(調(diào)用方法:對(duì)象.send(方法名,參數(shù)))
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)
- 動(dòng)態(tài)定義
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'
代碼塊
...
類(lèi)宏
如果按照以前的做法,定義一個(gè)屬性的讀寫(xiě)必須將每個(gè)屬性定義一個(gè)Get 和 Set方法,比如如下代碼
class Post
def title=(title)
@title = title
end
def title
@title
end
....
....
如果像一篇文章這樣,定義title,content,author等屬性,就需要寫(xiě)3組這樣的方法,非常不方便。這個(gè)時(shí)候,就要亮出Ruby的類(lèi)宏attr_accessor(module的類(lèi)里面的一個(gè)C語(yǔ)言寫(xiě)的方法,附上超鏈接,以上代碼就可以寫(xiě)成
class Post
attr_accessor :title
end