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