写点什么

透视 Ruby 1.9 的 Lambda 函数

2008 年 1 月 22 日

Ruby 的 Block 块是它的关键特色之一,用块能够写出简明且高度可重用的算法。即使没有别的用处,它至少消弱了人们对循环敬畏的态度。这个概念在其他语言和理论中还被称为:

这是个十分令人迷惑的词汇,因为闭包这个词汇还指对代码作用域的捕获。而块则不需要捕获这个作用域——例如下面的代码

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.new {} 或lambda {} 来创建块。虽然还不至于恐怖,但这样会使代码冗长,而且还引入了一些不受欢迎的词汇把代码搞得凌乱不堪。(注意: Proc.new {}lambda {}也有些微妙的不同,但本文不关注它们)。

在特定情况下可能变通的方法。例如,如果一个 API 调用需要多个块,辅助函数就会嵌入到类中,这样就产生了两个作用:a) 辅助了块 b) 带有貌似命名参数的负作用:

find (predicate {|x,y| x < y}, predicate{|x,y| x > 20})

其中 predicate函数仅仅是:

def predicate(&b)<br></br> b <br></br>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|时就会工作失常。代码如下:[…]

<span color="#013694"><span color="#013694"><span color="#000000"><span color="#013694"><span color="#000000">class SandBox<br></br> def abc(*args)<br></br>  yield(*args)<br></br> end<br></br>define_method :xyz do<br></br> |*args, &block|<br></br>  block.call(*args)<br></br> end<br></br>end<br></br>SandBox.new.abc(1,2,3){|*args| p args} # => [1, 2, 3]</span></span></span></span></span>

这段代码在 Ruby 1.8.x 下无法运行——它在解析阶段就失败了:

<span color="#013694"><span><span><span color="#013694"><span color="#000000">benchmark3.rb:8: syntax error, unexpected ',', expecting '|' <br></br>define_method :xyz do |*args, &block|<br></br>  ^ <br></br>benchmark3.rb:11: syntax error, unexpected kEND, expecting $end</span></span></span></span></span>

在 Ruby 1.9 中,它可以正常运行。

1.9 的另外一个变化就是修复了一个早就发现的问题: 现在块参数局部的了。看这段代码:

foo = "Outer Scope"<br></br>[1,2,3].each{|foo|<br></br> foo = "I'm not local to this block" <br></br>}<br></br>puts foo在 1.8 中,这段代码会输出"I’m not local to this block",而在 1.9 中,输出为"Outer Scope"。简而言之,现在块像我们期望的那样工作了:块参数遮住了块外的同名变量。(我们先来问自己一个问题:“如何访问外部域的变量”。你不能—— 仅为块参数选择一个不同的名字)。

你怎么看 Ruby 1.9 中 lambda 和块的变化?它们涉及了我们一直关注的问题了吗?还有没有遗留的问题?

提示: 查看 InfoQ 上所有 Ruby 1.9 相关的文章

查看英文原文: The state of the Lambda in Ruby 1.9

2008 年 1 月 22 日 08:082440
用户头像

发布了 33 篇内容, 共 33370 次阅读, 收获喜欢 0 次。

关注

评论

发布
暂无评论
发现更多内容

《从0到1学习Flink》—— Flink parallelism 和 Slot 介绍

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 你上传的 jar 包藏到哪里去了?

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink JobManager 高可用性配置

zhisheng

大数据 flink 流计算

Flink 从0到1学习 —— 如何使用 Side Output 来分流?

zhisheng

大数据 flink 流计算

【迁移】用Redlock构建Redis分布式锁【译】

罗琦

分布式锁

《从0到1学习Flink》—— Data Sink 介绍

zhisheng

大数据 flink 流计算

Flink 从0到1学习—— Flink 不可以连续 Split(分流)?

zhisheng

大数据 flink 流计算

重学 Java 设计模式:实战工厂方法模式

小傅哥

设计模式 小傅哥 重构 架构设计 工厂模式

《从0到1学习Flink》—— Mac 上搭建 Flink 1.6.0 环境并构建运行简单程序入门

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Data Source 介绍

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 写入数据到 Kafka

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Apache Flink 介绍

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 如何自定义 Data Sink ?

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink Data transformation(转换)

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 介绍Flink中的Stream Windows

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 项目如何运行?

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 读取 Kafka 数据写入到 RabbitMQ

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 配置文件详解

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 如何自定义 Data Source ?

zhisheng

大数据 flink 流计算

【迁移】撸论文系列之——Bigtable

罗琦

论文阅读 bigtable

如果你想做汽车开发,请先看看这篇。

水滴

自动驾驶 软件开发 开发

【迁移】读完了GFS论文之后的感悟

罗琦

大数据 GFS 论文阅读

《从0到1学习Flink》—— Flink 写入数据到 ElasticSearch

zhisheng

大数据 flink 流计算

聊一聊采访外籍人员时需要注意的几点事项

李冬梅

态度 体验 感悟

【迁移】CQRS很难吗?(译文:底部有原文地址)

罗琦

领域驱动设计 DDD

勇攀监控高峰-EMonitor之根因分析

乒乓狂魔

监控 全链路监控 故障定位 根因分析 AIOPS

《从0到1学习Flink》—— Flink 读取 Kafka 数据批量写入到 MySQL

zhisheng

大数据 flink 流计算

Flink 从0到1学习—— 分享四本 Flink 国外的书和二十多篇 Paper 论文

zhisheng

大数据 flink 流计算

Deno会在短期内取代Node吗?

Geek_Willie

node.js SpreadJS deno

【迁移】Flink vs Spark

罗琦

flink spark 大数据处理

《从0到1学习Flink》—— Flink 中几种 Time 详解

zhisheng

大数据 flink 流计算

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

透视Ruby 1.9的Lambda函数-InfoQ