2013-02-08 31 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