我正在寻找一种在Ruby中"映射"单个项目的方法.
我想调用这个函数并传递一个块,该对象将被生成块,然后块的结果将返回给调用者.究竟是什么地图,但对于单个元素.
动机是有时你会生成仅用于构造其他东西的对象.然后不再需要原始对象.将转换放入块中并消除临时值会很好.
作为一个人为的例子,让我们假设我想创建一个表示月/年组合的整数.对于今天的日期,代码看起来像:
day = Date.today
month_number = day.year * 100 + day.month
Run Code Online (Sandbox Code Playgroud)
如果我可以这样做,我真的很喜欢它:
month_number = Date.today.some_function { |d| d.year * 100 + d.month }
Run Code Online (Sandbox Code Playgroud)
但我不知道'some_function'是什么(或者它是否存在).
如果有更多的Ruby方式来处理这样的事情,我会全神贯注.我知道猴子修补类,但我希望处理那些更短暂的情况.
jon*_*ohn 18
instance_eval 是你在找什么.
month_number = Date.today.instance_eval { |d| d.year * 100 + d.month }
Run Code Online (Sandbox Code Playgroud)
的|d|也是可选的,并且self默认为对象上下文.
这可以以更紧凑的方式满足您的需求.
month_number = Date.today.instance_eval { year * 100 + month }
Run Code Online (Sandbox Code Playgroud)
saw*_*awa 15
使用instance_evalas jondavidjohn的答案是一种方法,但它有重新分配的开销self.这个功能曾经在Ruby核心中被提出过,但被拒绝并被撤回.使用Ruby开发人员之一(Akinori MUSHA)提供的解决方案,您可以这样写:
month_number = Date.today.tap{|d| break d.year * 100 + d.month}
Run Code Online (Sandbox Code Playgroud)
使用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)
Run Code Online (Sandbox Code Playgroud)
自 Ruby 2.5(2017 年底)和 Ruby 2.6 起,这个问题有了新的答案,分别是yield_self和then。
根据文档,这些方法将 self 交给块并返回块的结果。
\n以你的问题为例
\nmonth_number = Date.today.then { |d| d.year * 100 + d.month }\nRun Code Online (Sandbox Code Playgroud)\nmonth_number截至撰写本文之日,将为202207 \xe2\x80\x93。
在较新的 Ruby 版本中,这些方法Object 已从Kernel. 它们看起来是一样的;不过,我不知道为什么他们没有别名或类似的东西。