亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Ruby > 正文

Ruby元編程之夢中情人method_missing方法詳解

2020-10-29 19:38:45
字體:
來源:轉載
供稿:網友

我最近讀了些文章(比如這篇),宣傳在 Ruby 里使用 method_missing 的。

很多人都與 method_missing 干柴烈火,但在并沒有小心處理彼此之間的關系。所以,我想來探討一下這個問題:

** 我該怎么用 method_missing **

什么時候該抵擋 method_missing 的誘惑

首先,永遠不要在還沒花時間考慮你用得夠不夠好之前,就向 method_missing 的魅力屈服。你知道,在日常生活中,很少會讓你以為的那樣亟需 method_missing:

日常:方法代理

案例:我需要讓這個類能夠使用另一個類的方法

這是我所見過最普遍的使用 method_missing 的情況。這在 gems 與 Rails 插件里頭尤其流行。它的模型類似這樣:

復制代碼 代碼如下:

class A
  def hi
    puts "Hi from #{self.class}"
  end
end

class B
  def initialize
    @b = A.new
  end

  def method_missing(method_name, *args, &block)
    @b.send(method_name, *args, &block)
  end
end

A.new.hi #=> Hi from A
B.new.hi #=> Hi from A


如此,B 就擁有了 A 的所有實例方法。但是讓我們想想,在調用 @b.hi 的時候都發生了什么。你的 ruby 環境沿著繼承鏈一路找 hi 這個方法,到最后,恰恰在丟出個 NoMethodError 前,它調了 method_missing 這個方法。

在上例中,情況并不壞,畢竟這里就兩個微不足道的類需要查。但通常,我們是在 Rails 或者其他一些框架的上下文中編程。而你的 Rails 模型繼承自 ActiveRecord,而它又集成自其他一大坨的類,于是現在你就有了一坨高高的堆棧要爬⋯⋯ 在你每次調用 @b.hi 的時候!

你的好基友:define_method

估計現在你在抱怨,“但是史蒂夫,我需要 method_missing” 我告訴你,別忘了其實除了情婦之外,你還有個忠誠的好基友,叫做 define_method。

它允許你動態地定義一個方法(顧名思義)。它的偉大之處在于,在它執行過之后(通常在你的類們加載之后),這些方法就存在你的類中了,簡單直接。在你創建這些方法的時候,也沒有什么繼承鏈需要爬。

define_method 很有愛很可靠,并且能夠滿足你的日常生活。不信我?接著看⋯⋯

復制代碼 代碼如下:

class B
  define_method(:hi) do
    @b.hi
  end
end

“可是我有一大坨方法要定義!” 你抱怨

“沒問題!” 我賣萌眨眼

復制代碼 代碼如下:

class B
  [:hi, :bye, :achoo, :gesundheit].each do |name|
    define_method(name) do
      @b.send(name)
    end
  end
end

可是我懶得把它們一個個寫出來!

你有點難搞哦

復制代碼 代碼如下:

class A
  # ... lots of methods in here
end
class B
  A.instance_methods.each do |name|
    define_method(name) do
      @b.send(name)
    end
  end
end

那假如我要定義的方法跟原本的有那么一些些不一樣呢?

容易

復制代碼 代碼如下:

class A
  def hi
    puts "Hi."
  end
end

class B
  A.instance_methods.each do |name|
    define_method("what_is_#{name}") do
      if @b.respond_to?(name)
        @b.send(name)
      else
        false
      end
    end
  end
end

B.new.what_is_hi #=> "Hi."
B.new.what_is_wtf #=> false


呃,代碼看起來不優雅啊

那就沒辦法了,湊合得了。如果你想要代碼更易讀,可以看看我們的ruby delegation library 和 Rails ActiveRecord delegation。

好,我們總結一下,看看 define_method 的真正威力。

修改自 ruby-doc.org 上的 例子

復制代碼 代碼如下:

class A
  def fred
    puts "In Fred"
  end
  def create_method(name, &block)
    self.class.send(:define_method, name, &block)
  end
  define_method(:wilma) { puts "Charge it!" }
end
class B < A
  define_method(:barney, instance_method(:fred))
end

a = B.new
a.barney                                #=> In Fred
a.wilma                                 #=> Charge it!
a.create_method(:betty) { p self.to_s }
a.betty                                 #=> B


什么時候用 method_missing?

現在你估計在想,總有該用它的時候吧,不然還要它干嘛?沒錯。

動態命名的方法(又名,元方法)

案例:我要依據某種模式提供一組方法。這些方法做的事情顧名思義。我可能從來沒有調用過這些可能的方法,但是等我要用的時候,它們必須可用。

現在才是人話!這其實正是 ActiveRecord 所采用的方式,為你提供那些基于屬性的動態構建的查找方法,比如 find_by_login_and_email(user_login, user_email)。

復制代碼 代碼如下:

def method_missing(method_id, *arguments, &block)
  if match = DynamicFinderMatch.match(method_id)
    attribute_names = match.attribute_names
    super unless all_attributes_exists?(attribute_names)
    if match.finder?
      # ...you get the point
    end # my OCD makes me unable to omit this
    # ...
  else
    super # this is important, I'll tell you why in a second
  end
end

權衡利弊

當你有一大堆元方法要定義,又不一定用得到的時候,method_missing 是個完美的折衷。

想想 ActiveRecord 中基于屬性的查找方法。要用 define_method 從頭到腳定義這些方法,ActiveRecord 需要檢查每個模型的表中所有的字段,并為每個可能的字段組合方式都定義方法。

復制代碼 代碼如下:

find_by_email
find_by_login
find_by_name
find_by_id
find_by_email_and_login
find_by_email_and_login_and_name
find_by_email_and_name
# ...

假如你的模型有 10 個字段,那就是 10! (362880)個查找方法需要定義。想象一下,在你的 Rails 項目跑起來的時候,有這么多個方法需要一次定義掉,而 ruby 環境還得把它們都放在內存里頭。

老虎?伍茲都做不來的事情。

** 正確的 method_missing 使用方式

(譯者猥瑣地注:要回家了,以下簡要摘譯)

1、先檢查

并不是每次調用都要處理的,你應該先檢查一下這次調用是否符合你需要添加的元方法的模式:

復制代碼 代碼如下:

def method_missing(method_id, *arguments, &block)
  if method_id.to_s =~ /^what_is_[/w]+/
    # do your thing
  end
end

2、包起來

檢查好了,確實要處理的,請記得把函數體包在你的好基友,define_method 里面。如此,下次就不用找情婦了:

復制代碼 代碼如下:

def method_missing(method_id, *arguments, &block)
  if method_id.to_s =~ /^what_is_[/w]+/
    self.class.send :define_method, method_id do
      # do your thing
    end
    self.send(method_id)
  end
end

3、擦屁股

自己處理不來的方法,可能父類有辦法,所以 super 一下:

復制代碼 代碼如下:

def method_missing(method_id, *arguments, &block)
  if method_id.to_s =~ /^what_is_[/w]+/
    self.class.send :define_method, method_id do
      # do your thing
    end
    self.send(method_id)
  else
    super
  end
end

4、昭告天下

復制代碼 代碼如下:

def respond_to?(method_id, include_private = false)
  if method_id.to_s =~ /^what_is_[/w]+/
    true
  else
    super
  end
end

要告訴別人,你的類雖然暫時還沒有這個方法,但是其實是能夠響應這方法的。

** 總結 **

在每個 Ruby 程序員的生活中,這仨方法扮演了重要的角色。define_method 是你的好基友,method_missing 是個如膠似漆但也需相敬如賓的情婦,而 respond_to? 則是你的愛子,如此無虞。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久久网站| 91久久精品国产91久久性色| 岛国av午夜精品| 亚洲人成网在线播放| 57pao国产精品一区| 尤物精品国产第一福利三区| 岛国av一区二区在线在线观看| 亚洲综合在线小说| 亚洲精品影视在线观看| 久久亚洲电影天堂| 欧美日韩国产一区二区三区| 欧美日韩日本国产| 国产欧美日韩中文字幕| 欧美成人激情在线| 久久免费少妇高潮久久精品99| 日韩激情av在线播放| 国产一区二区三区在线播放免费观看| 精品欧美aⅴ在线网站| 7777精品视频| 亚洲午夜未满十八勿入免费观看全集| 日韩av免费在线看| 尤物九九久久国产精品的特点| 日韩精品中文字幕在线观看| 欧美日韩在线第一页| 久久黄色av网站| 91av在线免费观看| 国产成+人+综合+亚洲欧美丁香花| 国产日韩欧美在线视频观看| 国产精品久久久久久久久久免费| 欧美中文字幕精品| 夜夜嗨av一区二区三区免费区| 国产亚洲一区二区在线| 欧美亚洲一级片| 日韩人在线观看| 久久精品视频网站| 98午夜经典影视| 日韩在线中文视频| 久久久精品2019中文字幕神马| 亚洲一区国产精品| 国产精品久久久久久av下载红粉| 色综合伊人色综合网| 欧美色道久久88综合亚洲精品| 中文字幕欧美国内| 国产精品户外野外| 秋霞成人午夜鲁丝一区二区三区| 韩日精品中文字幕| 九九九热精品免费视频观看网站| 国产99视频在线观看| 欧美成人免费在线观看| 亚洲第一色中文字幕| 久久久成人的性感天堂| 人人爽久久涩噜噜噜网站| 最新91在线视频| 一区二区三区日韩在线| 日韩激情av在线免费观看| 亚洲新声在线观看| 色小说视频一区| 国产欧美一区二区三区久久人妖| 国产美女91呻吟求| 日韩精品999| 欧美一区深夜视频| 久久激情视频久久| 国产精品黄色影片导航在线观看| 欧美电影免费观看大全| 国产美女扒开尿口久久久| 欧美黑人巨大精品一区二区| 国产一区二区美女视频| www.日韩av.com| 国产精品精品视频一区二区三区| 亚洲国产精品中文| 日本不卡免费高清视频| 中文字幕日本精品| 欧美高清电影在线看| 欧美日韩国产黄| 亚洲性线免费观看视频成熟| 青青青国产精品一区二区| 激情成人中文字幕| 亚洲国产精品大全| 91性高湖久久久久久久久_久久99| 欧美国产日本在线| 欧美午夜性色大片在线观看| 亚洲另类激情图| 91国产美女视频| 亚洲白拍色综合图区| 日韩av123| 国产精品三级美女白浆呻吟| 伊人久久久久久久久久久久久| 日本国产高清不卡| 国产美女久久精品香蕉69| 亚洲电影免费观看高清| 精品美女久久久久久免费| 亚洲午夜精品久久久久久久久久久久| 国产欧美日韩最新| 欧美日韩中国免费专区在线看| 欧美午夜美女看片| 欧美一区三区三区高中清蜜桃| 91午夜理伦私人影院| 亚洲欧洲日本专区| 乱亲女秽乱长久久久| 亚洲成人教育av| 国产视频观看一区| www.美女亚洲精品| 国产欧美日韩中文| 米奇精品一区二区三区在线观看| 国产成人在线视频| 亚洲老板91色精品久久| 国产视频自拍一区| 91人成网站www| 久久久精品国产一区二区| 国产suv精品一区二区| 成人免费xxxxx在线观看| 成人av在线天堂| 最近2019年日本中文免费字幕| 欧美日韩在线视频一区| 91精品国产综合久久香蕉| 亚洲第一免费网站| 一区二区三区视频观看| 久久精品视频免费播放| 精品亚洲一区二区三区在线观看| 国产精品福利小视频| 中文字幕精品影院| 欧美亚洲视频在线观看| 欧美激情视频在线免费观看 欧美视频免费一| 欧美激情视频一区| 亚洲精品久久久久久久久久久久| 一区二区三区精品99久久| 国产欧美欧洲在线观看| 亚洲欧美在线看| 91在线高清视频| 久久精品亚洲国产| 麻豆乱码国产一区二区三区| 日本电影亚洲天堂| 日韩电影大片中文字幕| 蜜月aⅴ免费一区二区三区| 欧美影院在线播放| 亚洲aⅴ男人的天堂在线观看| 久久激情五月丁香伊人| 黑人巨大精品欧美一区二区一视频| 伊人久久久久久久久久久| 久久久久免费视频| 97久久超碰福利国产精品…| 最近中文字幕2019免费| 亚洲第一国产精品| 26uuu另类亚洲欧美日本一| 亚洲男人的天堂在线播放| 欧美国产日韩一区二区| 国产中文字幕日韩| 欧美色xxxx| 欧美裸体xxxx| 在线成人激情视频| 亚洲精品一区久久久久久| 亚洲精品资源美女情侣酒店| 国产精品成人免费电影| 日韩av在线网站| 亚洲a∨日韩av高清在线观看| 成人性生交大片免费观看嘿嘿视频| 国产精品久久久久77777| 国产脚交av在线一区二区| 精品国产一区二区三区久久久狼| 亚洲成色www8888| 久久久亚洲影院你懂的| 日韩亚洲欧美中文高清在线| 国产欧美一区二区| 在线精品视频视频中文字幕|