Ruby元編程

  • 類(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

Eval方法

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

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

  • 對(duì)象模型 所有class定義之外的代碼默認(rèn)運(yùn)行在頂級(jí)對(duì)象main中。 打開(kāi)類(lèi) ruby的class更像是一個(gè)作用于...
    五月的約修亞閱讀 3,536評(píng)論 0 4
  • 什么時(shí)候需要讀這本書(shū)? 掃過(guò)一遍基本的 Ruby 語(yǔ)法,自己也寫(xiě)過(guò)一些 Ruby 代碼,覺(jué)得 Ruby 也就是一個(gè)...
    Forelax閱讀 562評(píng)論 0 4
  • 打開(kāi)類(lèi) 在Ruby中,定義類(lèi)的語(yǔ)句和其他語(yǔ)句沒(méi)有本質(zhì)區(qū)別,你可以在類(lèi)定義中放置任何語(yǔ)句。 Ruby的class關(guān)鍵...
    CharlesZhangCh閱讀 502評(píng)論 0 0
  • 01 Ruby元編程介紹和使用場(chǎng)景02 Ruby的類(lèi)結(jié)構(gòu)03 Singleton Method單例方法以及supe...
    Jayzen閱讀 1,072評(píng)論 0 4
  • 1、APP名稱(chēng)您的 App 在 App Store 中顯示的名稱(chēng)。名稱(chēng)長(zhǎng)度不能超過(guò) 50 個(gè)字符。 2、描述對(duì)您 ...
    我是小胡胡123閱讀 1,682評(píng)論 0 0

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