第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Ruby 的元編程

如果您使用了一段時間 Ruby,那么到目前為止,您可能已經(jīng)聽到很多次“元編程”這個詞了。在元編程的章節(jié)中,我會由淺入深帶大家了解 Ruby 的元編程。

[TOC]

1. 什么是元編程

元編程是計算機程序的編寫,這些計算機程序?qū)⑵渌绦颍ɑ蛩鼈儽旧恚┳鳛閿?shù)據(jù)寫入或操作,或者在編譯時完成部分工作,而這些工作原本可以在運行時完成。

在許多情況下,這使程序員可以在與手動編寫所有代碼相同的時間內(nèi)完成更多工作,或者為程序提供更大的靈活性,以有效地處理新情況而無需重新編譯。

或者,更簡單地說:元編程是編寫在運行時編寫代碼的代碼,以使您的編程更輕松。

這聽上去是不是很瘋狂?

簡而言之,您可以使用元編程來重新打開和修改類,捕獲不存在的方法并即時創(chuàng)建它們,通過避免重復(fù)創(chuàng)建DRY(Don’t repeat yourself)代碼等等。

Ruby常見的開源框架比如RailsSinatra都使用了元編程這門技術(shù)。

2. 元編程的例子

編程中的一項重要哲學(xué)是 DRY(不要重復(fù)自己)。多次編寫相同(或相似)的代碼不僅浪費時間,而且在將來需要進(jìn)行更改時可能會成為一個極大的困擾。在許多情況下,可以通過編寫為您編寫代碼的代碼來消除這種重復(fù)工作。

這是一個示例:考慮一個汽車制造商的應(yīng)用程序,該應(yīng)用程序可以存儲和訪問每個模型的數(shù)據(jù)。在應(yīng)用程序中,我們有一個名為CarModel的類:

# Example 1
class CarModel
  def engine_info=(info)
    @engine_info = info
  end

  def engine_info
    @engine_info
  end

  def engine_price=(price)
    @engine_price = price
  end

  def engine_price
    @engine_price
  end

  def wheel_info=(info)
    @wheel_info = info
  end

  def wheel_info
    @wheel_info
  end

  def wheel_price=(price)
    @wheel_price = price
  end

  def wheel_price
    @wheel_price
  end

  def airbag_info=(info)
    @airbag_info = info
  end

  def airbag_info
    @airbag_info
  end

  def airbag_price=(price)
    @airbag_price = price
  end

  def airbag_price
    @airbag_price
  end

  def alarm_info=(info)
    @alarm_info = info
  end

  def alarm_info
    @alarm_info
  end

  def alarm_price=(price)
    @alarm_price = price
  end

  def alarm_price
    @alarm_price
  end

  def stereo_info=(info)
    @stereo_info = info
  end

  def stereo_info
    @stereo_info
  end

  def stereo_price=(price)
    @stereo_price = price
  end

  def stereo_price
    @stereo_price
  end
end

每個汽車模型都具有各種功能,例如“立體聲”,“警報”等。我們提供了一種獲取和設(shè)置汽車每個特征值的方法。每個功能都有信息和價格,因此對于我們添加到CarModel類中的每個新功能,我們需要定義兩個新方法:feature_infofeature_price。由于每種方法都相似,因此我們可以執(zhí)行以下操作來簡化此代碼:

# Example 2
class CarModel
  FEATURES = ["engine", "wheel", "airbag", "alarm", "stereo"]

  FEATURES.each do |feature|
    define_method("#{feature}_info=") do |info|
      instance_variable_set("@#{feature}_info", info)
    end

    define_method("#{feature}_info") do
      instance_variable_get("@#{feature}_info")
    end

    define_method "feature_price=" do |price|
      instance_variable_set("@#{feature}_price", price)
    end

    define_method("#{feature}_price") do
      instance_variable_get("@#{feature}_price")
    end
  end
end

在此示例中,我們首先定義一個名為FEATURES的數(shù)組,其中包含我們希望為其添加方法的所有功能。

然后,對于每個功能,我們使用Ruby的Module#define_method為每個功能定義四個方法。就像示例1中一樣,四種方法是獲取功能價格和信息的getter和setter方法。唯一的區(qū)別是,它們是在定義類時動態(tài)編寫的,而不是由我們動態(tài)編寫的。我們使用Object#instance_variable_set()設(shè)置每個功能的實例變量的值,并使用Object#instance_variable_get返回每個功能的實例變量的值。

# Example 3
class CarModel
  attr_accessor :engine_info, :engine_price, :wheel_info, :wheel_price, :airbag_info, :airbag_price, :alarm_info, :alarm_price, :stereo_info, :stereo_price
end

定義這樣的getter和setter方法的需求在Ruby中很常見,因此Ruby已經(jīng)擁有可以做到這一點的方法也就不足為奇了。只需一行代碼,即可使用Module#attr_accessorattr_accessor被稱為為類宏class macro))與示例2中的功能相同。

這已經(jīng)很好了,但我們還可以更完美一點。

對于每個功能,我們?nèi)匀恍枰x兩個屬性(feature_info和feature_price)。

理想情況下,我們應(yīng)該能夠調(diào)用一個與示例7相同的方法,但只需列出每個功能一次即可

# Example 4
class CarModel
  # define a class macro for setting features
  def self.features(*args)
    args.each do |feature|
      attr_accessor "#{feature}_price", "#{feature}_info"
    end
  end

  # set _info and _price methods for each of these features
  features :engine, :wheel, :airbag, :alarm, :stereo
end

在此示例中,我們采用CarModel#features的每個參數(shù),并將它們傳遞給具有_price_info擴(kuò)展名的attr_accessor。

盡管這種方法比示例3中的方法稍微復(fù)雜一些,但它可以確保每個功能都被視為相同,并且意味著將來添加更多屬性將更加簡單。

注意事項:您可以使用元編程做一些非??岬氖虑椋缬煤苌俚拇a行添加大量功能,需要注意的是,您一定要注意代碼的可讀性,過度的元編程會使您的代碼難以理解和調(diào)試。

這看起來是不是很高大上,讓我們開始元編程的學(xué)習(xí)吧~

3. 小結(jié)

本節(jié)我們學(xué)習(xí)了什么是元編程,并用一個實例來講解了什么是元編程的概念,下節(jié)課我們正式進(jìn)入元編程的其他知識點學(xué)習(xí)。