在C#中,你可以做這樣的事情:紅寶石相當於C#的‘產量’關鍵字,或者創建序列沒有預先分配存儲
public IEnumerable<T> GetItems<T>()
{
for (int i=0; i<10000000; i++) {
yield return i;
}
}
這將返回1000個整數的枚舉序列而沒有分配集合在這段長度的記憶中。
有沒有辦法在Ruby中做同樣的事情?我試圖處理的具體示例是將矩形數組展平爲要列舉的值序列。返回值不一定是Array
或Set
,而是某種只能按順序迭代/枚舉的序列,而不是索引。因此,整個序列不需要同時分配在內存中。在.NET中,這是IEnumerable
和IEnumerable<T>
。
因爲我對.NET術語更熟悉,所以在Ruby世界中使用的術語的任何說明都會有所幫助。
編輯
也許我原來的問題是不是真的足夠清晰的 - 我認爲yield
在C#中非常不同的含義和Ruby是混亂的原因這裏的事實。
我不想要一個解決方案,需要我的方法來使用塊。我想要一個具有實際返回值的解決方案。返回值可以方便地處理序列(過濾,投影,連接,壓縮等)。
這裏是get_items
的我怎麼可能用一個簡單的例子:
things = obj.get_items.select { |i| !i.thing.nil? }.map { |i| i.thing }
在C#中,任何方法返回IEnumerable
使用一個yield return
使編譯器生成迎合這種行爲幕後有限狀態機。我懷疑Ruby的延續可能會實現類似的效果,但我還沒有看到過一個例子,而且我不清楚自己會如何做到這一點。
確實似乎有可能使用Enumerable
來實現此目的。一個簡單的解決方案是給我們一個Array
(其中包括模塊Enumerable
),但我不想在內存中創建一個包含N個項目的中間集合,因爲它可能只是懶惰地提供它們,並且完全避免任何內存高峯。
如果這仍然沒有意義,那麼考慮上面的代碼示例。 get_items
返回一個枚舉,調用select
。傳遞給select
的是一個知道如何在需要時提供序列中下一個項目的實例。重要的是,整個項目的收集尚未計算。只有當select
需要一個項目時,它會要求它,get_items
中的潛在代碼將啓動並提供它。這個懶惰攜帶鏈,這樣select
只有在map
要求它時從序列中提取下一項。因此,一次可以對一個數據項執行長鏈操作。實際上,以這種方式構造的代碼甚至可以處理無限的數值序列,而不會有任何種類的內存錯誤。
所以,這種懶惰很容易用C#編碼,我不知道如何在Ruby中做到這一點。
我希望更清晰(我會盡量避免寫的問題在凌晨3點以後。)
@Matthew,這看起來正是我想要的。太糟糕了,它是Ruby 1.9,因爲我目前在1.8.7。將看看我是否可以升級。如果你知道1.9以前的方法,我想聽聽它。 –
根據這篇文章http://www.rubyinside.com/ruby-187-released-912.html的'Enumerator'序列的支持已經回移植到1.8.7。快樂的時光。 –