2013-02-08 62 views
10

我正在尋找一種方法來在Ruby中映射單個項目。單個對象的Ruby映射()

我想調用這個函數並將它傳遞給一個塊,該對象將被放到塊中,然後塊的結果將返回給調用者。到底是什麼地圖,但只是一個單一的元素。

的動機是,有時你會生成只用於構造別的東西的對象。原來的對象不再需要。將轉換放到一個塊中並消除臨時值將會很好。

作爲一個人爲的例子,我們假設我想創建一個代表月份/年份組合的整數。對於今天的日期,代碼看起來是這樣的:

day = Date.today 
month_number = day.year * 100 + day.month 

我真的很喜歡它,如果我可以這樣做:

month_number = Date.today.some_function { |d| d.year * 100 + d.month } 

但我不知道什麼是「some_function」是(或者它甚至存在)。

如果有更多的Ruby方式來處理這樣的事情,我全都耳熟能詳。我知道猴子補丁類,但我正在尋找處理那些更短暫的情況。

+0

['對象#tap'](http://ruby-doc.org/core-1.9.3/Object.html#method-i-tap)是如此接近,但它不」 t返回塊的值... – maerics 2013-02-08 20:30:31

+1

有點像? m = lambda {| d | d.year * 100 + d.month} .call(Date.today) – Kaeros 2013-02-08 20:30:53

+0

請參閱@jondavidjohn的答案。內置且無需proc綁定開銷。 – 2013-02-08 20:42:47

回答

13

instance_eval是你在找什麼。

month_number = Date.today.instance_eval { |d| d.year * 100 + d.month } 

|d|也是可選的,並且self默認爲對象上下文。

這可能以更緊湊的方式滿足您的需求。

month_number = Date.today.instance_eval { year * 100 + month } 
+1

謝謝!這正是我需要的。 – 2013-02-08 20:43:16

+0

它看起來像| d |也是可選的(自我將是塊執行期間的實例)。所以下面也會工作:Date.today.instance_eval {year * 100 + month} – 2013-02-08 20:53:18

+0

謝謝,它爲我工作。 – 2013-05-16 07:17:05

3

Ruby的內建Object#tap已關閉,但它不返回塊的值。

這裏有一個想法:

class Object 
    def sap 
    yield self 
    end 
end 

eleven = 10.sap { |x| x + 1 } # => 11 
month_number = Date.today.sap { |d| d.year * 100 + d.month } # => 201202 
+0

如果你不是一半的話,你爲什麼要猴子補丁?請參閱下面的答案。 – jondavidjohn 2013-02-08 20:38:09

+1

對於一個很好的簡短語法,+1,但我認爲@jondavidjohn使用instance_eval由於內置而更加正確。 – 2013-02-08 20:41:22

+2

儘管'instance_eval'的作用相當,它也揭示了目標對象的成員變量,打破界面/實施障礙。這不是一個安全問題,而是意外地將你的腳踢掉的機會。恕我直言猴修補在這種情況下是合理的。 – maerics 2013-02-09 06:36:26

15

使用instance_evaljondavidjohn的回答是一條路可走,但它有開銷重新分配self。這種功能曾經是proposed in Ruby core,但被拒絕並被撤回。使用由Ruby開發者KNU(彰德武者)的一個呈現在那裏的解決方案,你可以這樣寫:

month_number = Date.today.tap{|d| break d.year * 100 + d.month} 

使用tap,你需要做的唯一的額外放break在塊的開始。


require 'benchmark' 

n = 500000 
Benchmark.bm do |x| 
    x.report{n.times{Date.today.instance_eval{year * 100 + month}}} 
    x.report{n.times{Date.today.instance_eval{|d| d.year * 100 + d.month}}} 
    x.report{n.times{Date.today.tap{|d| break d.year * 100 + d.month}}} 
end 

     user  system  total  real 
    2.130000 0.400000 2.530000 ( 2.524296) 
    2.120000 0.400000 2.520000 ( 2.527134) 
    1.410000 0.390000 1.800000 ( 1.799213) 
+1

+1最有可能被核心團隊青睞的答案。我仍然在學習Ruby的一些細節,從塊中突破的行爲對我來說是新的。在這種情況下,我誠實地發現語言的行爲令人不快。基準爲 – 2013-02-09 20:43:22

+1

+1。謝謝! – 2013-06-20 14:22:55