亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Ruby2.1中Refinements特性有哪些

發布時間:2022-01-14 14:44:59 來源:億速云 閱讀:120 作者:iii 欄目:大數據

這篇文章主要介紹“Ruby2.1中Refinements特性有哪些”,在日常操作中,相信很多人在Ruby2.1中Refinements特性有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Ruby2.1中Refinements特性有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

Monkey Patches(猴子補丁)一直是Ruby Open Class(開放類)特性的副作用, 不過也有人把Monkey Patches看作是Ruby的一種特性。為什么叫「猴子補丁」呢? 進化未完全唄,這也是Ruby社區中傳出來的名字,不管如何,這個命名代表著貶義,意味著危險。

Ruby的開放類給開發者以很大的自由與靈活,但是,當你打開一個類,添加自己的方法的時候,你有沒有想過這個方法會覆蓋掉已有的方法,自己寫的代碼還好,但是你如果用Ruby內建的類,或者是第三方gem提供的類,Monkey Patches隨時有可能讓你的代碼穿越。

有一個比較典型的案例,早年的Ruby1.8.7 preview版本之前,是沒有Symbol#to_proc這個方法的,但是Rails自己通過Monkey Patch實現了Symbol#to_proc方法,結果Ruby1.8.7preview版本之后,添加了Symbol#to_proc方法,導致了Rails出現了一些不對勁的問題。

在Refinements出現之前,Ruby社區避免Monkey Patches的方法基本有以下幾種:

  • 使用別名/ alias_method_chain

  • 使用module 加命名空間

  • 強制檢查要添加的方法是否被定義

Ruby社區里討論了好多年的Refinements特性,就是為了解決上述問題,讓你安全的使用開放類。直到Ruby2.0才加進來這個特性,但是屬于實驗性的,不建議使用,但是前兩天隨著Ruby2.1穩定版的發布,Refinements特性解除了實驗狀態,意味著Ruby團隊支持建議你去使用Refinements特性了,但是比較悲劇的是, Refinements的文檔沒有跟上,你要去看文檔學習這個新特性的話,多半會出錯。

下面我總結了一下Ruby2.1中Refinements的大致用法,如有遺漏,請告訴我。

一、普通青年使用Refinements的方式:

 
# refinements提供一種方法,讓類的修改只影響到某個作用域

#判斷一個字符串是不是數字型字符串
module NumberQuery
  refine String do
    def number?
      !!match(/^[0-9]+$/)
    end
  end
end

# 并不是定義了就能用的
class A
  def a(n)
    n.respond_to?(:number?)
  end
end

A.new.a "123"  #=> 這里會返回false,意味著沒有定義number?方法

# 你必須用Module#using 方法
class A
  using NumberQuery 
end

# 你以為打開A類,using NumberQuery就可以了? 你太天真了。
A.new.a “123”  #=> false

# 看清楚,你必須重新定義A#a方法
class A
  using NumberQuery
  def a(n)
    n.respond_to?(:number?)  #=> true
  end
end

A.new.a "123" #=> 返回true,證明number?方法可以用了。

可見, 你使用了Module#refine方法打開類去增加的方法,只能使用Module#using方法在需要使用這個補丁的地方,引入補丁模塊,才可以使用。而且,注意上面的示例代碼,你必須在類定義的原始地方去using NumberQuery才起作用。這有點類似java或.net中的概念,Classboxes,即classbox的修改只對本classbox(或者導入它的 classbox)是可見的,這個特性我們稱之為本地重綁定(local rebinding)。 C#里ms也有一個using,用于擴展方法, C#的擴展方法僅僅在其顯式導入的代碼中才是可見的, 這也和我們上面的Ruby示例相似。所以Ruby中的Refinements算是改進版的Classboxes了。

二、二逼青年使用Refinements的方式

 
module NumberQuery
  refine String do
    def number?
      !!match(/^[0-9]+$/)
    end
  end
end

然后:

 
class String
  using NumberQuery
  def other_method
    puts "hello" if number?
  end
end

當然,這不會造成String類全局的污染,只限于other_method方法,但是,請注意,你是不是有慣性的打開類進行Monkey Patches了?

有人可能這么用:

 
class T
  refine String do
    def number?
      !!match(/^[0-9]+$/)
    end
  end
end

哥,拜托,這樣是會報錯的:

 
  NoMethodError: undefined method `refine' for T:Class

這意味著,你不能在一個類中去使用refine。

還有人有點小聰明,他這么用:

 
# 我這個模塊,不僅僅是打補丁的啊,還有其他方法
module NumberQuery
  refine String do
    def number?
      !!match(/^[0-9]+$/)
    end
  end
 
  def hello
    puts "world".number?
  end
end

# 那么我在class A中,除了using,還得include
class A
  using NumberQuery
  include NumberQuery
end

這樣是行不通的, 還是去學學普通青年的用法吧,NumberQuery#hello方法中使用的number?是不合法的。

還有人在想,這多麻煩啊,還得寫兩遍模塊的名字,有了,我用included方法:

 
module NumberQuery
  def self.included(base)
    base.send(:using, self)
  end
 
  refine String do
    def number?
      !!match(/^[0-9]+$/)
    end
  end
 
  def hello
    puts "world"
  end
end

# 這樣,我就可以只include一次NumberQuery模塊了。
class A
  include NumberQuery
end

打住吧,兄弟,你又犯二了,睜大眼睛看看報的什么錯吧!

有位兄弟,想定義個類方法:

 
module NumberQuery
  refine String do
    def self.number?(str)
      !!str.match(/^[0-9]+$/)
    end
  end
end

class A
  using NumberQuery
  def a
    String.number?("123")
  end
end

A.new.a #=> NoMethodError: undefined method `number?' for String:Class

傻眼了吧? 呵呵,告訴你正確的定義類方法的用法:

 
module NumberQuery
  refine String.singleton_class do
    def number?(str)
      !!str.match(/^[0-9]+$/)
    end
  end
end

class A
  using NumberQuery
  def a
    String.number?("123")
  end
end

A.new.a #=> true

這次正常了。

Refinements還有個容易令Rubyist犯二的地方,就是你refine的方法,如果和類中的方法重名,還是會重寫掉那個方法的,當然你可以也使用super。

 
module NumberQuery
  refine String do
    def to_s
      to_i
    end
  end
end

class A
  using NumberQuery
  def a
    "123".to_s
  end
end

String#to_s的方法被修改了,唉,難道這又是Monkey Patches的節奏? 不。 它只在A#a這個方法內有用,不會污染到全局,但是你在碰到類似情況的時候,一定要注意。當然,在A的子類,也會被傳下去,除非a方法被重寫。

 
class B < A; end
B.new.a #=> 123

#當子類B中,重寫的a方法之后:
class B < A
  def a
    "123".to_s
  end
end
B.new.a #=> "123"

#除非你在B類也使用refine補丁
class B < A
  using NumberQuery
  def a
    "123".to_s
  end
end
B.new.a #=> 123

還有個值得說明的地方,就是,using的模塊,不會被掛到繼承樹(祖先樹/ancestors tree)上:

 
module NumberQuery
  refine String do
    def number?
      !!match(/^[0-9]+$/)
    end
  end
end

class A
  using NumberQuery
  def a
    "123".number?
  end
end

A.ancestors #=>  [A, Object, Kernel, BasicObject]

可以看到, NumberQuery并沒有被掛到祖先樹上。

到此,關于“Ruby2.1中Refinements特性有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

若羌县| 汝南县| 广宁县| 昭通市| 饶河县| 镇康县| 龙海市| 保亭| 调兵山市| 浮山县| 洛阳市| 阆中市| 和顺县| 廊坊市| 清水河县| 高青县| 天长市| 安岳县| 安化县| 水城县| 百色市| 昂仁县| 泸州市| 平度市| 三都| 定边县| 龙海市| 迁西县| 布尔津县| 盐边县| 上虞市| 裕民县| 嘉祥县| 滦南县| 济宁市| 庄河市| 团风县| 墨脱县| 土默特左旗| 滨州市| 威远县|