Ruby 2.7 新發布,新功能說明
就如往常,Matz 選在聖誕節發布 Ruby 2.7 作為聖誕禮物,那麼這個新版本有什麼特別的呢?又有什麼是未來整個 Ruby 社群的方向呢?
Ruby 2.7 的新功能列表
- IRB 多行模式與即時文件查閱
- Array#intersection
- Enumerable#tally
- Enumerable#filter_map
- Enumerable#produce
- Block 預設參數名稱(實驗性)
- Pattern Matching(實驗性)
- Compaction GC
- Keyword Argument
根據 Matz 的說法,本次的版本為最後的 2.x 版本,下個版本將會直接跳到從 2016 開始大家就在引頸期盼的 Ruby 3.0!
下面是 Matz 在 RubyConf 2019 上針對 Ruby 2.7 的說明。
下面,我們開始逐一說明本次 Ruby 2.7 的新功能。
IRB 多行模式與即時文件查閱
新版 irb 支援了多行編輯的功能,只要按 alt-enter 即可換行繼續編輯,我們可以從上面的影片知道,按方向鍵往上可以將整個 block 重新叫回來編輯,另外,按一次 tab 會提示可用的關鍵字,連續按多次 tab 可以進入文件模式,在互動模式下快速查找 rdoc,之後開發者可以在不用離開互動模式的狀況下進行文件的查詢,也可以鼓勵開發者在開發程式的時候編寫 rdoc 。
Array#intersection
這並不完全算是一個新功能,這是一個簡寫,在 Ruby 2.6 引進一個兩個新功能:union
與 difference
,在 Ruby 2.7 中更進一步將其簡化了,使用方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Enumerable#tally
回傳一個 Hash ,其中為給定之 Array 中內容物與其個數。
1
|
|
會回傳
1
|
|
Enumerable#filter_map
filter_map
method 想要將 select
與 map
結合,從字面上,我們可以知道,這個 method 會回傳一個經過條件選擇的新 Array。
在過去我們如果要做到相同的效果的話,一般都需要使用 chain method 的方式來達到:
1
|
|
在 Ruby 2.7 中我們可以這樣做
1
|
|
Enumerable#produce
這個功能需要一點點想想力才有辦法理解,讓我們先來看一下此功能的 proposal:
“This method produces an infinite sequence where each next element is calculated by applying the block to the previous element.”
沒錯,這個 method 理論上會回傳一個無限長的 Array,讓我看看下面的範例:
1 2 |
|
這個 method 長這樣的:Enumerator.produce(initial, &block)
,預設上 initial 即為 1 ,我們亦可不傳入值,注意到我們後面的 block 為需要產生這個 Enumerable 的條件,而最後不管我們有沒有給定 take(5)
在記憶體裡面都是一個無限長的大小,只是最後回傳的時候給出最前面五筆,這邊需要特別注意使用,可能在大型產品上會有記憶體管理方面的問題產生。
Block 預設參數名稱(實驗性)
Ruby 從 Scala, Closure, Groovy 借鏡了 Block 的預設參數名稱,規則很簡單:第一個參數的預設名稱即為 _1
、第二個參數即為 _2
⋯以此類推,下面是一個簡單的範例:
1 2 3 |
|
你仍舊可以在一般的區域變數使用「底線加上數字」做為變數名稱,但是 compiler 會跳出警告,告訴你這樣是不好的行為,請盡量不要這樣做。
Pattern Matching(實驗性)
在演講中,Matz 提到,像是 Pattern Matching 這樣的 Functional Programming 行為,對於 Ruby 來說需要一個全局的重新思考,或許目前的行為在之後會與目前通通不同。在那之前,讓我們看看目前 Ruby 2.7 所提供的 Pattern Matching 使用方法。
Pattern Matching 會回傳一個布林值,當 Pattern 相同時,則會回傳 true 反之亦然。下面是幾個簡單的範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Compaction GC
在 Ruby 2.7 中引入了記憶體壓縮垃圾蒐集演算法,意即將碎片化的記憶體重組的垃圾蒐集演算法,在一些多執行緒程式執行的過程中,可能會造成記憶體使用上的碎片化,長久下來會造成高記憶體使用與效能的下降。
新的 GC method GC.compact
期望能夠將 heap 的碎片化降到最低。
詳細內容請見原 proposal
Keyword Argument
這是 Ruby 2.7 與 Ruby 2.6 以前最重要的不同!
未來 Ruby 3 之後將不向下相容 Ruby 2.6 的 Keyword Argument
Ruby 2.6 以前的 keyword argument 行為如下
1 2 3 4 5 6 7 8 9 |
|
這真的是非常地令人崩潰的行為,上面的 function 呼叫行為應該是以下這幾種問題的綜合:
- Wrong Number of Arguments
- Combination of Optional/ Rest Argument
- Combination with Hash Argument
但是 Ruby VM 卻沒有吐出錯誤訊息,所以在 Ruby 2.7 開始,這樣的行為將會被拋棄,在 Ruby 2.7 時只會吐出警告訊息,但是在 Ruby 3 之後就不能執行了,所以 Library 的開發者,如果有使用到這樣的行為,請儘速更新您的軟體,以符合未來的 Ruby 版本。
Reference
- Ruby 3x3: Matz, Koichi, and Tenderlove on the future of Ruby Performance, https://blog.heroku.com/ruby-3-by-3
- Ruby 2.7.0 Released, https://www.ruby-lang.org/en/news/2019/12/25/ruby-2-7-0-released/
- Ruby Progress Report by Yukihiro Matsumoto(Matz), https://www.youtube.com/watch?v=2g9R7PUCEXo
- New Features, Methods & Improvements in Ruby 2.7, https://www.rubyguides.com/2019/12/ruby-2-7-new-features
- Enumerator.generate proposal, https://bugs.ruby-lang.org/issues/14781
- Ruby 2.7 adds Enumerator#produce, https://blog.saeloun.com/2019/11/27/ruby-2-7-enumerator-produce.html
- Manual Compaction for MRI’s GC (
GC.compact
), https://bugs.ruby-lang.org/issues/15626