Enumerator <> 一旦上了船,程式就是不會背叛你的夥伴

[Day30] 還在等什麼!快來成為 Ruby 工程師啊!(誤)

終於來到鐵人賽的最後一天了!以為我要寫個完賽心得帶過嗎?雖然很想這樣做,不過,這裡並不是停下腳步的地方啊!

這篇要介紹的是 Enumerator


Enumerator 是什麼?

剛開始看到這個詞只覺得陌生 + 困惑

上網查了許久,Enumerator 似乎沒有一個很精準的中文翻譯,但可以找到像是 external, iterator, Enumerable Module 這些關鍵字。

但其實它一直都在我們身邊。

平時 coding 可能就已經看過它,那就是當使用 each 方法操作陣列相關的物件時,又不小心忘了寫 Block 的話:

1
2
[1,2,3].each
=> #<Enumerator: [1, 2, 3]:each>

就會出現這個 Enumerator ! 可是···這是什麼意思?還是不懂。

沒關係把 Enumerator 放一邊,先來看看 Enumerable 能不能輔助我理解。


Enumerable 又是什麼?

雖然和上一個概念相比,似乎只有單字詞性的變化,不過 Enumerable 的概念明確許多。

首先,Enumerable 是一種模組(Module),又可以稱為「列舉」,來瞧瞧 Ruby 官方文件的定義:

列舉提供陣列和雜湊搜尋、排序或轉換集合內元素的功能。而陣列或雜湊必須各自提供一個方法,該方法可以產生集合的連續成員···(?)

簡單來說,像是 each, select, map, match, sort, grep 這些常用的方法都屬於 Enumerable 的範疇。

詳細內容請參考 Ruby-Doc Module: Enumerable


External Iterator

接下來介紹外部迭代器(External Iterator)

大部分時候我們都在做的是 Internal Iterator
像是平常在丟迴圈,或是上在介紹的陣列方法,都屬於 Internal Iterator ,譬如想從一個陣列中選取一些元素:

1
2
3
4
5
6
7
list = [1, 2, 3, 4]

list.select do |n|
n > 2
end

#=> [3, 4]

不過,既然有 Internal ,也就有 ExternalInternal Iterator 是由陣列或雜湊這類的集合物件控制,而 External Iterator 則是由外部來控制,像是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
icons = %w[up down].to_enum(:cycle)
list = [1, 2, 3, 4, 5]

list.each do
puts icons.next
end

# =>
up
down
up
down
up
=> [1, 2, 3, 4, 5]

在這段程式碼裡,icons 被指定使用 cycle 方式在做迭代,所以當 next 到最後一個元素,下一次的 next 就會從頭再來過。


所以,什麼是 Enumerator?

我這邊引用五倍紅寶石 DC 助教的原話:

Enumerator 最簡單的解釋是 Enumerable 加上 External Iteration,而 EnumeratorEnumerable 的合作方式是前者負責產生、儲存資料,『需要時』再以後者的方法運用。

譬如:

1
2
3
4
5
list = [1,2,3].each
#=> #<Enumerator: [1, 2, 3]:each>

list.select { |x| x.odd? }
#=> [1, 3]

除了這種彈性的用法之外,Enumerator 的另一個特性是能把物件不斷串起來,以最近超紅的電影《天能》為例:

1
2
3
4
5
6
7
8
9
'TENET'.split('').reverse_each.with_index(1) do |word, index|
puts "#{word}"
end
T
E
N
E
T
=> ["T", "E", "N", "E", "T"]

果然是天能!時光回溯!


結語

Enumerator 的概念不是很好理解,在尋找文獻和研究的過程中不斷撞牆,似乎勉勉強強地看懂了一些,但仍拼湊不出全貌,不過身為工程師,主動接觸一些不熟悉的概念是應該的。

之後的文章應該會放在 Medium 或是自己架的部落格,期許往後的路上還要學得更多,並時常接觸自己不熟悉的領域以及運用所學,天啊!這種既掙扎又興奮的感覺真是太棒了!

那,鐵人賽就先到這邊啦!
在出發的那一刻,我們就已經得到 ONEPIECE 了!


參考來源
與你每天擦身而過的 Enumerator