在规则引擎中,Ruby 的闭包使用特别频繁,而且有 block,Proc和 lambda 等后几种形式的用法,很让人困惑。为了深入理解代码,再次认真学习了一下 Ruby 的闭包,特别是 block,proc 和 lambda 几种用法的异同,这次的周记就和大家分享一下心得。
闭包是 Ruby 相对其它语言特别优势之一,很多语言有闭包,但是唯有 Ruby 把闭包的优势发挥得淋漓尽致。Ruby 的哲学之一:同一个问题现实中有多种解决方法,所以 Ruby 中也有多种解法,所以闭包的使用也有多种方法。
先看一个代码的例子:
Example 1:
def foo1 yield enddef foo2(&b) b.call if b end
foo1 { puts "foo1 in block" } foo2 { puts "foo2 in block" } proc = Proc.new { puts "foo in proc" } foo1(&proc) foo2(&proc) lambda_proc = lambda { puts "foo in lambda" } foo1(&lambda_proc) foo2(&lambda_proc)
输出:
》foo1 in block 》foo2 in block 》foo in proc 》foo in proc 》foo in lambda 》foo in lambda
大家是不是有些困惑,首先是方法 foo1 和 foo2 都能接收闭包,它们这两种写法有什么区别,然后是作为参数的三种闭包 block,proc和 lambda有什么区别。
1. yield 和 block call 的区别
yield 和 block call 两种都能实现运行闭包,从实际运行效果来说,区别不大。其区别主要在于:
1.1 闭包的传递和保存
因为闭包已经传递到参数里,所以可以继续传递或保存起来,例如:
Exampl 2:
class A def foo1(&b) @proc = b end def foo2 @proc.call if @proc end enda = A.new a.foo1 { puts "proc from foo1" } a.foo2
1.2 性能
yield不是方法调用,而是 Ruby 的关键字,yield 要比 block call 比快 1 倍左右。
2. block 和 proc, lambda 的区别
很简单直接,引入 proc 和 lambda 就是为了复用,避免重复定义,例如在 example 1 中,使用 proc 变量存储闭包,避免重复定义两个 block 。
3. proc 和 lambda 的区别
这大概是最让人困惑的地方,从 Example 1 的行为上看,他们的效果是一致的,为什么要用两种不同的表达方式。
proc = Proc.new { puts "foo in proc" } lambda_proc = lambda { puts "foo in lambda" }
确实,对于简单的情况,比如 Example 1的情况,他们的行为是一致的,但是主要在两个地方有明显差异:
1.1 参数检查
还是例子说话 Example 3:
def foo x = 100 yield x endproc = Proc.new { |a, b| puts "a is #{a.inspect} b is #{b.inspect}" } foo(&proc)
lambda_proc1 = lambda { |a| puts "a is #{a.inspect}" } foo(&lambda_proc1) lambda_proc2 = lambda { |a, b| puts "a is #{a.inspect} b is #{b.inspect}" } foo(&lambda_proc2)
输出
》a is 100 b is nil 》a is 100 》ArgumentError: wrong number of arguments (1 for 2) …
可见,proc 不会对参数进行个数匹配检查,而 lambda 会,如果不匹配还会报异常,所以安全起见,建议优先用 lambda。
1.2 返回上层
还是例子说话 Example 4:
def foo f = Proc.new { return "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" enddef bar f = lambda { return "return from lambda" } puts f.call # control does not leave bar here return "return from bar" end
puts foo puts bar
输出
》return from foo from inside proc 》return from lambda 》return from bar
可见,proc 中,return 相当于执行了闭包环境里的 return,而 lambda 只是返回call 闭包所在环境。
总结:闭包是 Ruby 的强大特性,它的几种表达方式block,proc 和 lambda有细微差别,要用好它需要对其深入理解。
本文向大家介绍Ruby中使用Block、Proc、lambda实现闭包,包括了Ruby中使用Block、Proc、lambda实现闭包的使用技巧和注意事项,需要的朋友参考一下 闭包(Closure),是指未绑定到任何对象的自由代码,闭包中的代码与任何对象和全局变量无关,只与执行此段代码的上下文相关。 今天我们简要的看一下ruby中的闭包实现。 Ruby中的闭包实现有:Block,Proc,Lamb
本文向大家介绍block、inline、inline-block的区别?相关面试题,主要包含被问及block、inline、inline-block的区别?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: block元素会独占一行,多个block元素会各自新起一行。默认情况下,block元素宽度自动填满其父元素宽度。 block元素可以设置width,height属性。块级元素即使设置了宽度
问题内容: 创建Jade模板时,块和使用include有什么区别?什么时候使用另一种? 问题答案: 块是占位符。它的内容来自另一个玉文件。包含也是占位符。它的内容也来自另一个玉器文件。 到目前为止,两者是平等的。 但: 包括嵌入完整文件。包含文件定义要包含的文件。因此,对于将始终以相同方式加载的诸如页脚或页眉之类的外包零件来说,include是很好的选择。 块仅在顶部文件中定义一个占位符。包含哪些
本文向大家介绍Ruby中的Proc类及Proc的类方法Proc.new的使用解析,包括了Ruby中的Proc类及Proc的类方法Proc.new的使用解析的使用技巧和注意事项,需要的朋友参考一下 Proc是对块及其context(局部变量的作用域以及栈框架)进行对象化处理之后得到的过程对象。您可以像使用无名函数那样来使用Proc,但它不会导入局部变量的作用域(可以把动态局部变量用作Proc局部变量
hadoop在默认的情况下,split和hdfs的block的大小是一样的,这样容易造成误解认为两者是一样的,下面说下两者的区别和联系: split是MapReduce里的概念,是切片的概念,split是逻辑切片 ;而block是hdfs中切块的大小,block是物理切块; split的大小在默认的情况下和HDFS的block切块大小一致,为了是MapReduce处理的时候减少由于split和bl
本文向大家介绍详解Ruby中的代码块对象Proc,包括了详解Ruby中的代码块对象Proc的使用技巧和注意事项,需要的朋友参考一下 Proc对象 Proc是由块转换来的对象。创建一个Proc共有四种方法,分别是: 示例代码 除了上面的四种之外,还有一种通过&操作符的方式,将代码块与Proc对象进行转换。如果需要将某个代码块作为参数传递给方法,需要通过为这个参数添加&符号,并且其位置必须是在参数的最