Ruby
![](/icons/6361de.gif)
Block块是它
![](/icons/6361de.gif)
关键特色的
![](/icons/6361yi.gif)
![](/icons/6361dou.gif)
用块能够写出简明且高度可重用
![](/icons/6361de.gif)
算法
![](/icons/6361dou2.gif)
即使没有别
![](/icons/6361de.gif)
用处
![](/icons/6361dou.gif)
它至少消弱了人们对循环敬畏
![](/icons/6361de.gif)
态度
![](/icons/6361dou2.gif)
这个概念在其他语言和理论中还被称为:
◆lambda
![](/icons/6361hanshu.gif)
◆匿名
◆闭包(参见Java 7中lambda
![](/icons/6361hanshu.gif)
所使用
![](/icons/6361de.gif)
名称)
这是个十分令人迷惑
![](/icons/6361de.gif)
词汇
![](/icons/6361dou.gif)
![](/icons/6361yinwei.gif)
闭包这个词汇还指对代码作用域
![](/icons/6361de.gif)
捕获
![](/icons/6361dou2.gif)
而块则不需要捕获这个作用域——例如下面
![](/icons/6361de.gif)
代码:
x = lambda {|x,y| x + y}
没有使用自由变量(没有绑定
![](/icons/6361de.gif)
变量;参数列表中正式声明x和y)
![](/icons/6361dou.gif)
因此无须创建
![](/icons/6361yi.gif)
个闭包
块在其他语言中有很多种多样
![](/icons/6361de.gif)
表现形式
![](/icons/6361dou.gif)
有
![](/icons/6361de.gif)
简洁有
![](/icons/6361de.gif)
冗长
![](/icons/6361dou2.gif)
比如对Ruby影响深远
![](/icons/6361de.gif)
LISP语言
![](/icons/6361dou.gif)
所使用
![](/icons/6361de.gif)
块语法为:
(lambda (arg) "hello world")
对Ruby
![](/icons/6361de.gif)
设计产生影响
![](/icons/6361de.gif)
另
![](/icons/6361yi.gif)
种语言Smalltalk
![](/icons/6361dou.gif)
采用方括号来简洁地表达语法:
[arg| ^"hello world"]
Ruby中
![](/icons/6361dou.gif)
块
![](/icons/6361de.gif)
最方便也最常使用
![](/icons/6361de.gif)
语法是作为
![](/icons/6361hanshu.gif)
![](/icons/6361de.gif)
参数
![](/icons/6361dou2.gif)
它允许简单地在
![](/icons/6361hanshu.gif)
名后面添加
![](/icons/6361yi.gif)
个用do/end 或者花括号{ / }包围
![](/icons/6361de.gif)
代码块
![](/icons/6361dou2.gif)
例如:
5.times {|x| puts x}
这非常
![](/icons/6361de.gif)
方便
![](/icons/6361dou.gif)
同时也产生了Builder这样
![](/icons/6361de.gif)
习惯性使用方法
![](/icons/6361dou2.gif)
Builder可以通过嵌套
![](/icons/6361de.gif)
块来很容易地创建分层
![](/icons/6361de.gif)
数据结构
![](/icons/6361dou2.gif)
(提示:就在
![](/icons/6361yi.gif)
月下旬InfoQ即将发表
![](/icons/6361yi.gif)
篇详细描述如何在Ruby中创建Builder
![](/icons/6361de.gif)
文章)
不过
![](/icons/6361dou.gif)
还有
![](/icons/6361yi.gif)
个问题:要传递
![](/icons/6361yi.gif)
个以上
![](/icons/6361de.gif)
块给
![](/icons/6361hanshu.gif)
或思路方法就没那么简单了
![](/icons/6361dou2.gif)
它可以实现
![](/icons/6361dou.gif)
但不能用这么短
![](/icons/6361de.gif)
语法
![](/icons/6361dou.gif)
得使用Proc.
![](/icons/6361new.gif)
{} 或lambda {} 来创建块
![](/icons/6361dou2.gif)
虽然还不至于恐怖
![](/icons/6361dou.gif)
但这样会使代码冗长
![](/icons/6361dou.gif)
而且还引入了
![](/icons/6361yi.gif)
些不受欢迎
![](/icons/6361de.gif)
词汇把代码搞得凌乱不堪
![](/icons/6361dou2.gif)
(注意:Proc.
![](/icons/6361new.gif)
{} 和 lambda {}也有些微妙
![](/icons/6361de.gif)
区别
![](/icons/6361dou.gif)
但本文不关注它们)
在特定情况下可能有变通
![](/icons/6361de.gif)
思路方法
![](/icons/6361dou2.gif)
例如
![](/icons/6361dou.gif)
如果
![](/icons/6361yi.gif)
个API
![](/icons/6361diaoyong.gif)
需要多个块
![](/icons/6361dou.gif)
辅助
![](/icons/6361hanshu.gif)
就会嵌入到类中
![](/icons/6361dou.gif)
这样就产生了两个作用:a) 辅助了块 b) 带有貌似命名参数
![](/icons/6361de.gif)
负作用:
find (predicate {|x,y| x < y}, predicate{|x,y| x > 20})
其中predicate
![](/icons/6361hanshu.gif)
仅仅是:
def predicate(&b) b end
它用来返回这个块
![](/icons/6361dou2.gif)
不论这是否合适或者不依赖于特定情况
![](/icons/6361dou2.gif)
在这种情况下
![](/icons/6361dou.gif)
下面
![](/icons/6361de.gif)
代码——毋庸置疑地——更能表达清楚
![](/icons/6361dou.gif)
也能起到相同
![](/icons/6361de.gif)
作用
![](/icons/6361dou2.gif)
find (lambda{|x,y| x < y}, lambda {|x,y| x > 20})
为什么呢?
![](/icons/6361yinwei.gif)
lambda泄露了实现它
![](/icons/6361de.gif)
细节——若带有
![](/icons/6361yi.gif)
个块参数
![](/icons/6361dou.gif)
就不需要额外
![](/icons/6361de.gif)
关键词
![](/icons/6361dou2.gif)
predicate
![](/icons/6361de.gif)
解决方案对代码做了注解
![](/icons/6361dou.gif)
并产生了lambda
![](/icons/6361dou2.gif)
需要明确
![](/icons/6361de.gif)
是
![](/icons/6361dou.gif)
这只是变通
![](/icons/6361de.gif)
思路方法
![](/icons/6361dou2.gif)
现在
![](/icons/6361dou.gif)
Ruby 1.9引入了
![](/icons/6361yi.gif)
个新
![](/icons/6361de.gif)
、更简洁
![](/icons/6361de.gif)
语法来创建lambda
![](/icons/6361hanshu.gif)
:
x = ->{puts "Hello Lambda"}
新
![](/icons/6361de.gif)
语法更加简短
![](/icons/6361dou.gif)
还抛弃了那个不知所云
![](/icons/6361de.gif)
术语lambda
![](/icons/6361dou2.gif)
需要明确
![](/icons/6361de.gif)
是
![](/icons/6361dou.gif)
这是个语法糖衣
![](/icons/6361dou2.gif)
不过它
![](/icons/6361de.gif)
确有助于写出可读性非常好
![](/icons/6361de.gif)
API代码
![](/icons/6361dou2.gif)
其中
![](/icons/6361yi.gif)
些API可以被称为“内部DSLs”
![](/icons/6361dou.gif)
尽管它们
![](/icons/6361de.gif)
定义都很模糊
![](/icons/6361dou2.gif)
出于这些
![](/icons/6361dou.gif)
新
![](/icons/6361de.gif)
lambda定义帮我们摆脱了那个夹在要么是纯领域要么是问题确定
![](/icons/6361de.gif)
代码中间
![](/icons/6361de.gif)
晦涩
![](/icons/6361de.gif)
术语“lambda”
Sidu Ponnappa报告了1.9中另外
![](/icons/6361yi.gif)
个语法变化:
在Ruby 1.9.0中
![](/icons/6361dou.gif)
在
![](/icons/6361yi.gif)
个块内显式
![](/icons/6361diaoyong.gif)
另
![](/icons/6361yi.gif)
个块
![](/icons/6361dou2.gif)
在上
![](/icons/6361yi.gif)
篇帖子中我没有提到这个思路方法
![](/icons/6361dou.gif)
![](/icons/6361yinwei.gif)
解析器
![](/icons/6361yi.gif)
遇到|*args, &block|时就会工作失常
![](/icons/6361dou2.gif)
代码如下:[..]
SandBox
def abc(*args)
yield(*args)
end
_method :xyz do
|*args, &block|
block.call(*args)
end
end
SandBox.
.abc(1,2,3){|*args| p args} # => [1, 2, 3]
这段代码在Ruby 1.8.x下无法运行——它在解析阶段就失败了:
benchmark3.rb:8: syntax error, unexpected ',', expecting '|'
_method :xyz do |*args, &block|
^
benchmark3.rb:11: syntax error, unexpected kEND, expecting $end
在Ruby 1.9中
![](/icons/6361dou.gif)
它可以正常运行
1.9
![](/icons/6361de.gif)
另外
![](/icons/6361yi.gif)
个变化就是修复了
![](/icons/6361yi.gif)
个早就发现
![](/icons/6361de.gif)
问题: 现在块参数是局部
![](/icons/6361de.gif)
了
![](/icons/6361dou2.gif)
看这段代码:
foo = "Outer Scope"
[1,2,3].each{|foo|
foo = "I'm not local to this block"
}
puts foo
在1.8中
![](/icons/6361dou.gif)
这段代码会输出"I'm not local to this block"
![](/icons/6361dou.gif)
而在1.9中
![](/icons/6361dou.gif)
输出为"Outer Scope"
![](/icons/6361dou2.gif)
简而言的
![](/icons/6361dou.gif)
现在块像我们期望
![](/icons/6361de.gif)
那样工作了:块参数遮住了块外
![](/icons/6361de.gif)
同名变量
![](/icons/6361dou2.gif)
(我们先来问自己
![](/icons/6361yi.gif)
个问题:“如何访问外部域
![](/icons/6361de.gif)
变量”
![](/icons/6361dou2.gif)
你不能—— 仅为块参数选择
![](/icons/6361yi.gif)
个区别
![](/icons/6361de.gif)
名字)
![](/icons/6361dou2.gif)
你如何看Ruby 1.9中lambda和块
![](/icons/6361de.gif)
变化?它们涉及了我们
![](/icons/6361yi.gif)
直关注
![](/icons/6361de.gif)
问题了吗?还有没有遗留
![](/icons/6361de.gif)
问题?
延伸阅读
最新评论