[eiffel 翻译 artima.com 访谈录]Ruby 语言中 blocks 和 Closure 结构

翻译 2004年02月03日 13:54:00
 

注: Matz 就是著名的编程语言 Ruby 的创始人(日本人)

 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

这段对话翻译自 artima.com 网站对 Matz 的访谈的第三部分。

 

英文文章原址: http://www.artima.com/intv/closures.html

 

 

未经本人同意,不要任何地方转载这篇翻译文章

(最先发表在本人的网站 http://www.eiffelqiu.com)。

 

 

使用 Blocks 做循环抽象

Bill Venners:

Ruby 支持 blocks Closure 结构. 什么是 blocks Closure 他们如何使用?

 

Yukihiro Matsumoto:

Blocks 基本上就是匿名函数。你可能熟悉诸如Lisp Python等其他语言中

Lambda 函数。 你可以向另外一个函数传递一个匿名函数,这个函数可以

调用这个被传递过来的匿名函数。例如, 函数可以通过一次传递给匿名函数一

个元素来执行循环迭代。在那些可以将函数当作第一类型的编程语言中,这是个

通常的方式,称为高排序函数样式。 Lisp 可以这样,Python 也是如此,甚至

就连C 也可以通过函数指针实现这点。很多其他语言也可以做这样的编程。

Ruby 中,不同之处只是在高排序函数语法风格上有所不同。在其他语言中,你

必须显示的指出一个函数可以接受另外一个函数作为参数。但是在Ruby 中,任何

方法都可以 Block 作为一个隐性参数被调用。在方法中,你可以使用 yield 关键字

和一个值来调用 block.

 

Bill Venners:

Block 的好处是什么?

 

Yukihiro Matsumoto:

基本上,Block 是被设计来做循环迭代抽象的。Block 最基本的使用就是让你

以自己的方式定义如何循环迭代。

 

例如,如果你有一个列表,序列,矢量组或者数组,你可以通过使用标准库中

提供的方法来实现向前循环迭代,但是如果你想从后往前实现循环迭代呢?如

果使用 C 语言,你得先设置四件事情:一个索引,一个起始值,一个结束条件

和一个递增变量。这种方式不好,因为它暴露了列表的内部实现方法,我们希

望能够隐藏内部逻辑,通过使用 Block 我们可以将内部循环迭代的方式隐藏在

一个方法或者函数中。比如,调用 list.reverse_each,你可以对一个列表实

现一个反向的循环迭代,而不需要知道列表内部是如何实现的。

 

Bill Venners:

就是说,我传递一个 Block 结构,这个 Block 中的代码可对循环迭代中每个

元素做任何事情,至于如何反向遍历就取决于List 本身了。换句话说,我就

是把原本在 C 语言 Loop 循环中写的那些代码作为一个 Block 来传递。

 

Yukihiro Matsumoto:

对,这意味着你可以定义许多迭代的方式。你可以提供一种向前循环迭代的方

式,一种向后循环迭代的方式,等等。这全取决于你了。C#也有迭代器,但是

它对于每个类只有一个迭代器。在 Ruby 中你可以拥有任意数量的迭代器。例

如,如果你有一个 Tree 类,可以让人以深度优先或者广度优先的方式遍历,

你可以通过提供两种不同的方法来提供两种遍历方式。

 

 

 

Bill Venners:

让我想想是否我了解了这点,在 Java 中,它们是通过 Iterator 接口实现抽

象迭代的,例如,调用程序可以让 Collection 来实现 Iterator。但是调用程

序必须使用循环来遍历Iterator 返回的元素。在 For 循环中, 我的代码实

现对每个循环迭代的元素的处理,这样循环语句将总是显示在调用程序中。 使

Block , 我并不调用一个方法来获取一个迭代器,我只是调用一个方法,同

时将我希望对循环迭代中每个要处理的元素的处理代码作为一个 Block 块结

构传递给该函数。 Block 的好处是不是将一些代码从调用程序中的 for 循环

中提取出来。

 

Yukihiro Matsumoto:

实现循环迭代的具体细节应该属于提供这个功能的类。调用程序应该尽可能的少

知道这些。这就是 Block 结构的本来目的。实际上,在早期版本的 Ruby 中,

使用 Block 的方法被称为迭代器,因为它们就是被设计来实现循环迭代的。但

是在 Ruby发展过程中,Block 的用途在后来已经得到了很大的增强,从最初的循环

抽象到任何事情。

 

Bill Venners:

例如。。。。

 

Yukihiro Matsumoto:

我们可以从Block 中创建一个 Closure 对象,一个 Closure 对象就是像 Lisp

中实现的那种匿名函数。 你可以向任何方法传递一个匿名函数(即 Closure)来

自定义方法的行为。另外举个例子,如果你有一个排序的方法用于排序数组或者

列表,你可以定义一个 Block 来定义如何在元素之间进行比较,这不是循环迭代。

这不是个循环,但是它使用了 Block 。

 

 

Bill Venners:

什么使得 Block 成为了一个 Closure?

 

Yukihiro Matsumoto:

Closure 对象包含可以运行的代码,是可执行的,代码包含状态,执行范围。

也就是说在Closure 中你捕捉到运行环境,即局部变量。因此,你可以在一个

Closure 中引用局部变量,即是在函数已经返回之后,他的执行范围已经销毁掉,

局部变量依然作为一部分存在于Closure 对象中,当没有任何对象引用它的时候,

垃圾搜集器将处理它,局部变量将消失。

 

Bill Venners:

这么说,局部变量基本上是被方法和Closure 对象共享的?如果 Closure 对象

更新了变量,方法可以看到,如果方法更新了变量,Cosure 对象也可以看到。

 

Yukihiro Matsumoto:

是的,局部变量在Closure 和方法之间共享,这是真正的 Closure,它不仅仅是

复制。

 

Bill Venners:

一个真正的 Closure 有什么好处?一旦我将一个 Block 变为一个 Closure,我

能用它做什么?

 

Yukihiro Matsumoto:

你可以将一个 Closure 转换为一个 Block,所以 Closure 可以被用在任何 Block

可以使用的地方。通常, Closure 用来将一个 Block 的状态保存在一个实例变量中,

因为一旦你将一个 Block 转换为一个 Closure, 它就是一个通过变量可以引用的对

象了。当然Closure 也可以像其他语言中那样使用 ,例如传递给对象以实现对方法

行为的定义。如果你希望传递一些代码来自定义一个方法, 你当然可以传递给它一个

Block. 但是如果你想将同样的代码传递给两个方法(当然这是非常少见的情况),但

是如果你确实想这么做,你可以将一个 Block 转换为一个 Closure ,将同一个 Closure

传递给多个方法。

 

 

 

Bill Venners:

原来如此,但是获取上下文环境有什么好处呢?真正让 Ruby 的 Closure 不同的是

它捕捉运行时间的上下文环境,局部变量等等。那么到底拥有上下文环境有什么好

处是我们无法通过传递给对象一个代码块所获得的呢?

Yukihiro Matsumoto:

实际上,说实在的,最主要的原因是向 Lisp 语言表达敬意, Lisp 提供了真正的

Closure 结构,所以我希望继续提供这个功能。

 

Bill Venners:

我看到的一个不同之处是: 数据在Closure 对象和方法之间共享。我想我可以在

一个常规的非 Closure 结构的 Block 中放入任何需要的环境数据作为参数来传

递,但是 Block 仅仅是对环境数据的一份复制,并不是真正的 Closure. 它并没有

共享环境数据。共享是Closure 和普通的传统函数对象不同的地方。

 

Yukihiro Matsumoto:

是的,共享允许你做一些有趣的代码演示,但是我觉得它对于程序员的日常工作并

没有想象的那么有用。这没什么太大的关系,例如像 Java 的内部类那样的普通复

制,在许多场合都在使用。但是通过 Ruby 的Clousure 结构,我希望表达我对Lisp 文化的致意。

 

 邱海峰(eiffelqiu)


mail: eiffel_q@163.com
www: http://www.eiffelqiu.com
weblog: http://mulder.5d.cn

[eiffel 翻译 artima.com 访谈录]Matz 关于技术的对话

[eiffel 翻译]Matz 关于技术的对话注: Matz 就是著名的编程语言 Ruby 的创始人(日本人) 这段对话翻译自 artima.com 网站对 Matz 的访谈的第四部分。英文文章原址:...
  • eiffelqiu
  • eiffelqiu
  • 2004年02月03日 13:54
  • 1083

[eiffel 翻译]采访 Ruby 创始人

导读:   注: Matz 就是著名的编程语言 Ruby 的创始人(日本人)   这段对话翻译自 oreillynet.com 网站对 Matz 的访谈。   未经本人同意,不要任何地方转载这篇翻译...
  • wozhilei
  • wozhilei
  • 2008年03月04日 18:48
  • 187

C语言中*和&的区别-代码实现说明

*是指针运算符,可以表示一个变量是指针类型;也可以表示一个指针变量的所指向的存储单元,可以获取某个地址存储的值。 &是取地址符号,既取得某一个变量的地址 int *p=&a; 或 int *p; p...
  • qq_20366761
  • qq_20366761
  • 2016年10月23日 19:51
  • 850

C语言中<>和“”有什么区别

例如你使用的是TurboC include 代表编译时直接在TurboC软件设置指定的路径(默认是TurboC所在文件夹下的include文件夹)中寻找里面是否有stdlib.h的库文件。如果有,直...
  • huayutiancheng
  • huayutiancheng
  • 2016年08月28日 19:53
  • 1320

C语言中的结构体与面向对象编程思想

没有万能的编程技术 没有只产生正确的结果的编程语言 不是每个项目的编程都是从零开始的 —-Object-Oriented Programming With ANSI-C 一、C语言结...
  • xiaohupashu
  • xiaohupashu
  • 2017年03月09日 20:12
  • 1163

C语言中<>和“”的区别

例如你使用的是TurboC include 代表编译时直接在TurboC软件设置指定的路径(默认是TurboC所在文件夹下的include文件夹)中寻找里面是否有stdlib.h的库文件。如果有,直...
  • xieyihua1994
  • xieyihua1994
  • 2016年09月29日 21:21
  • 1589

关于C语言中 || 和 &&的用法

||是逻辑或,例子如下 1 2 3 4 5 6 //表达式1||表达式2 //如果表达式1是true或者表达式2是true,...
  • Dy_1748204009
  • Dy_1748204009
  • 2016年12月13日 11:57
  • 4813

C语言-结构体的定义及使用

#include int main(int argc, char* argv[]) { //结构体数组的应用 struct student{ char name[2...
  • zhudong10
  • zhudong10
  • 2015年10月26日 22:02
  • 702

R语言编程结构

函数与控制结构相关: for结构: for (var in seq) statement 例如: for (i in 1:10) print(i) while结构: ...
  • yhb315279058
  • yhb315279058
  • 2015年10月26日 22:38
  • 754

C语言中引用及指针和引用的联系与区别

引用:引用是一个变量的另一个名字,又称别名。定义方式: int a=10; int &b=a;在这里,意思就是给a变量起了一个新名字b,因此b不可再次被重新定义。 引用必须初始化,无空引用,并且...
  • wtzdedaima
  • wtzdedaima
  • 2017年10月28日 16:51
  • 104
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[eiffel 翻译 artima.com 访谈录]Ruby 语言中 blocks 和 Closure 结构
举报原因:
原因补充:

(最多只允许输入30个字)