当我们想要将块传递给方法时,我们该怎么做:
block = Proc.new { puts 'test blocks & procs' }
def method(&block)
yield
end
VS
def method
yield
end
method { puts 'test blocks & procs' }
我们是否有任何特殊情况需要使用其中一种?
答案 0 :(得分:3)
使用Procs让你不要重复自己。比较一下:
arr1 = [1,2,3]
arr2 = [4,5,6]
使用块,重复两次块:
arr1.map { |n| n * 2 }
arr2.map { |n| n * 2 }
使用Procs时,您可以重复使用对象:
multiply_2 = Proc.new do |n|
n * 2
end
arr1.map(&multiply_2)
arr2.map(&multiply_2)
答案 1 :(得分:1)
1)块不是对象,因此无法在变量中捕获块,并且不能将块显式传递给方法。但是,您可以使用&
运算符将块转换为Proc实例,并且Proc实例是可以分配给变量并传递给方法的对象。
2)Proc.new()
没有返回一个块 - 它返回一个Proc实例。因此,命名变量块会产生误导。
3)yield
只调用一个块,这是在方法调用之后指定的东西:
do_stuff(10) {puts 'hello'} #<-- block
do_stuf(10) do |x| #<--'do' marks the start of a block
puts x + 2
end #<--end of block
block = Proc.new {puts 'hello'}
^
|
+--- #not a block
yield
不会调用碰巧作为参数传递给方法的Proc实例:
def do_stuff(arg)
yield
end
p = Proc.new { puts 'test blocks & procs' }
do_stuff(p)
--output:--
1.rb:2:in `do_stuff': no block given (yield) (LocalJumpError)
from 1.rb:6:in `<main>'
比较:
def do_stuff(arg)
puts arg
yield
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
I'm a block
4)您可以将块转换为Proc实例,并使用&amp ;,将其捕获到变量中,如下所示:
def do_stuff(arg, &p)
puts arg
p.call
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
I'm a block
骗子!你不再是一个街区了!通常,用于捕获块的变量名称写为&block
:
def do_stuff(arg, &block)
puts arg
block.call
end
但这在技术上是不正确的; block变量将包含一个Proc实例,如下所示:
def do_stuff(arg, &block)
puts arg
puts block.class
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
Proc
5)您也可以使用&
运算符将Proc实例转换为块,正如Nobita的答案所示:
def do_stuff(x, y)
yield(x, y)
end
p = Proc.new {|x, y| puts x+y}
do_stuff(10, 20, &p)
--output:--
30
在该示例中,方法调用do_stuff(10, 20, &p)
等同于编写:
do_stuff(10, 20) {|x, y| puts x+y}
6)您想何时使用block and yield
v。&block and call
?
捕获变量中的块的一个用例是,您可以将其传递给另一个方法:
def do_stuff(arg, &a_proc)
result = arg * 2
do_other_stuff(result, a_proc)
end
def do_other_stuff(x, p)
1.upto(x) do |i|
p[i] #Proc#[] is a synonym for Proc#call
end
end
do_stuff(2) {|x| puts x}
--output:--
1
2
3
4
我建议你遵守这两条规则:
yield
执行块。call
(或[]
)答案 2 :(得分:0)
基于以下基准测试,块似乎更快一些:
require 'benchmark/ips'
prc = Proc.new { '' }
def _proc(&block)
yield
end
def _block
yield
end
Benchmark.ips do |x|
x.report('Block') { _block { '' } }
x.report('Proc') { _proc(&prc) }
end
i7-4510U CPU @ 2.00GHz
的基准测试结果Block 149.700k i/100ms Proc 144.151k i/100ms Block 4.786M (± 1.6%) i/s - 23.952M Proc 4.269M (± 2.3%) i/s - 21.334M