Ruby元編程

  • 方法
  • 代碼塊
  • 類宏
  • Eval方法

實(shí)例變量、方法、類

實(shí)例變量(Instance Variables)是當(dāng)你使用它們時,才會被建立的對象。因此,即使是同一個類的實(shí)例,也可以有不同的實(shí)例變量。

從技術(shù)層面上來看,一個對象(實(shí)例)只是存儲了它的實(shí)例變量和其所屬類的引用。因此,一個對象的實(shí)例變量僅存在于對象中,方法(我們稱之為實(shí)例方法(Instance Methods))則存在于對象所屬的類中。這也就是為什么同一個類的實(shí)例都共享類中的方法,卻不能共享實(shí)例變量的原因了。

  • 類也是對象。
  • 因?yàn)轭愐彩且粋€對象,能應(yīng)用于對象的皆可運(yùn)用于類。類和任何對象一樣,有它們自己的類,Class類即是Class類的實(shí)例。
  • 與其它的對象一樣,類也有方法。對象的方法即是其所屬類的實(shí)例方法。亦即,任何一個類的方法就是Class類的實(shí)例方法。
  • 所有的類有共同的祖先Object類(都是從Object類直接或間接繼承而來),而Object類又繼承自BasicObject類,Ruby類的根本。
  • 類名是常量(Constant)。
  n = Class.new
  puts n.ancestors
  puts n.supperclass
  puts n.supperclass.supperclass
  puts n.supperclass.supperclass.supperclass

打開類

其實(shí)這個就跟方法重定義是一樣的結(jié)果,不過隨意改動可能會產(chǎn)生嚴(yán)重的后果,比如說你改的這個方法在其它地方有使用到,所以這種方法還是慎用,除非你非常明確該方法不會造成其它后果。

puts 'abc'.replace('a') # a
class String
  def replace(string)
    puts '重新打開了類'
  end
end
'abc'.replace('a')  #'重新打開了類'

我們也可以使用細(xì)化來實(shí)現(xiàn)這個過程

細(xì)化

module StringExtensions
  refine String do
    def replace(string)
       puts '細(xì)化'
    end
  end
end

在需要使用這個方法的地方使用using

如:using StringExtensions
細(xì)化的好處就是不會全局影響,在你需要使用的地方using就可以了,風(fēng)險相對較小。

調(diào)用方法

類中的方法是怎么調(diào)用的?

  • 方法的查找(接收者和祖先鏈)
    Ruby中要在類中查找一個方法,首先在它的類查找這個方法,如果沒有,則往上查找,如此類推,直到祖先鏈的頂端,到最后,如果還沒找到,會拋出method_missing異常。如果有了解過JS,那么你肯定非常明白這個過程,因?yàn)镴S中的方法查找也是類似于這個過程。
  • 執(zhí)行方法
    在執(zhí)行方法的過程中,Ruby始終需要一個接收者的引用,也就是self

self關(guān)鍵字

任何時刻,Ruby中只有一個對象能充當(dāng)當(dāng)前對象,并且沒有哪個對象能長期充當(dāng)這個角色,調(diào)用一個方法時,接收者就成為了self,從這一刻起,所有的實(shí)例變量都是self的實(shí)例變量,所有沒有明確指明接收者的方法都在self上調(diào)用。
舉個栗子:

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就充當(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?的方法為什么會報錯?
那是因?yàn)?self.is_my_book?(book) 等于 Book.is_my_book?(book)
當(dāng)b調(diào)用的時候,self引用b實(shí)例對象,不等于Book,所以就會拋出找不到方法的錯誤

方法

  • 動態(tài)派發(fā)(調(diào)用方法:對象.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)  
  • 動態(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'

代碼塊

...

類宏

如果按照以前的做法,定義一個屬性的讀寫必須將每個屬性定義一個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

Eval方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容