Ruby 何时使用方法{}vs方法(&;block)?
当我们希望将块传递给方法时,我们希望何时执行:Ruby 何时使用方法{}vs方法(&;block)?,ruby,Ruby,当我们希望将块传递给方法时,我们希望何时执行: block = Proc.new { puts 'test blocks & procs' } def method(&block) yield end VS 是否有任何特殊情况需要使用其中一种?使用Procs可以避免重复。比较一下: arr1 = [1,2,3] arr2 = [4,5,6] 使用块,可以重复块两次: arr1.map { |n| n * 2 } arr2.map { |n| n * 2 } 使用Proc
block = Proc.new { puts 'test blocks & procs' }
def method(&block)
yield
end
VS
是否有任何特殊情况需要使用其中一种?使用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)
使用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) 块不是对象,因此不能在变量中捕获块,也不能显式地将块传递给方法。但是,您可以使用&
运算符将块转换为过程实例,过程实例是一个可以指定给变量并传递给方法的对象
2) Proc.new()。因此,命名变量块是一种误导
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
与之相比:
def do_stuff(arg)
puts arg
yield
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
I'm a block
4) 您可以将块转换为Proc实例,并使用&,将其捕获到变量中,如下所示:
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) 何时要使用块并产生v<代码>&阻止并调用
在变量中捕获块的一个用例是,您可以将其传递给另一个方法:
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
执行块
如果Li 1不能为您工作,请考虑捕获块并使用<代码>调用< /代码>(或<代码> []/COD>)
1) 块不是对象,因此不能在变量中捕获块,也不能显式地将块传递给方法。但是,您可以使用&
运算符将块转换为过程实例,过程实例是一个可以指定给变量并传递给方法的对象
2) Proc.new()。因此,命名变量块是一种误导
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
与之相比:
def do_stuff(arg)
puts arg
yield
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
I'm a block
4) 您可以将块转换为Proc实例,并使用&,将其捕获到变量中,如下所示:
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) 何时要使用块并产生v<代码>&阻止并调用
在变量中捕获块的一个用例是,您可以将其传递给另一个方法:
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
执行块
如果Li 1不能为您工作,请考虑捕获块并使用<代码>调用< /代码>(或<代码> []/COD>)
基于以下基准,Block似乎要快一点:
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
2.00GHz下i7-4510U CPU上的基准测试结果
基于以下基准,Block似乎要快一点:
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
2.00GHz下i7-4510U CPU上的基准测试结果
你的第一个例子实际上没有任何作用。。。(从未运行过put
)您的第一个示例不应包含yield
,而应包含block.call
。目前,该方法忽略传入的块
变量,这就是为什么不输出任何内容。。。(从未运行过put
)您的第一个示例不应包含yield
,而应包含block.call
。目前,该方法忽略传入的块
变量,这就是不输出任何内容的原因。