我正在寻找一种在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 :(得分:17)
instance_eval
正是您要找的。 p>
month_number = Date.today.instance_eval { |d| d.year * 100 + d.month }
|d|
也是可选的,self
默认为对象上下文。
这可以更紧凑的方式满足您的需求。
month_number = Date.today.instance_eval { year * 100 + month }
答案 1 :(得分:16)
在instance_eval
的答案中使用jondavidjohn
是一种方法,但它有重新分配self
的开销。这样的特征曾经proposed in Ruby core,但被拒绝并被撤回。使用Ruby开发人员之一(Akinori MUSHA)提供的解决方案,您可以这样写:
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)
答案 2 :(得分:4)
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