在规则引擎中,Ruby 的闭包使用特别频繁,而且有 block,Proc和 lambda 等后几种形式的用法,很让人困惑。为了深入理解代码,再次认真学习了一下 Ruby 的闭包,特别是 block,proc 和 lambda 几种用法的异同,这次的周记就和大家分享一下心得。
闭包是 Ruby 相对其它语言特别优势之一,很多语言有闭包,但是唯有 Ruby 把闭包的优势发挥得淋漓尽致。Ruby 的哲学之一:同一个问题现实中有多种解决方法,所以 Ruby 中也有多种解法,所以闭包的使用也有多种方法。
先看一个代码的例子:
Example 1:
复制代码 代码如下:
def foo1
yield
end
def 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
end
a = 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
end
proc = 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"
end
def 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有细微差别,要用好它需要对其深入理解。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]