闭包是可以用作函数参数和方法参数的代码块。一直以来,这种编程结构都是一些语言(如 Lisp、Smalltalk 和 Haskell)的重要组成部分。尽管一些颇具竞争力的语言(如 C#)采纳了闭包,但 java 社区至今仍抵制对它的使用。本文探讨闭包在为编程语言带来一点点便利的同时是否也带来不必要的复杂性、闭包还有无更多的益处。
10 年前,我刚刚开始山地自行车运动的时候,我更愿意选用零件尽可能少尽可能简单的自行车。稍后,我意识到一些零件(如后减震器)可以保护我的背部和我自行车的框架在德克萨斯州高低起伏的山区中免受损害。我于是可以骑得更快,出问题的次数也渐少。虽然随之带来了操作上的复杂性和维护需求的增加,但对于我来说这点代价还是值得的。
关于本系列在 跨越边界系列 文章中,作者 BrUCe Tate 提出这样一种观点,即当今的 Java 程序员们通过学习其他方法和语言很好地武装了自己。自从 Java 技术明显成为所有开发项目的最佳选择以来,编程前景得以改变。其他框架影响着 Java 框架的构建方式,您从其他语言中学到的概念也可以影响 Java 编程。您编写的 Python(或 Ruby、Smalltalk 等语言)代码可以改变编写 Java 代码的方式。
本系列介绍与 Java 开发完全不同的编程概念和技术,但是这些概念和技术也可以直接应用于 Java 开发。在某些情况下,需要集成这些技术来利用它们。在其他情况下,可以直接应用这些概念。具体的工具并不那么重要,重要的是其他语言和框架可以影响 Java 社区中的开发人员、框架,甚至是基本方式。
关于闭包这个问题,Java 爱好者们现在陷入了类似的争论中。一些人认为闭包带给编程语言的额外复杂性并不划算。他们的论点是:为了闭包带来的一点点便利而打破原有语法糖的简洁性非常不值得。其他一些人则认为闭包将引发新一轮模式设计的潮流。要得到这个问题的最佳答案,您需要跨越边界,去了解程序员在其他语言中是如何使用闭包的。
Ruby 中的闭包
闭包是具有闭合作用域 的匿名函数。下面我会具体解释每个概念,但最好首先对这些概念进行一些简化。闭包可被视作一个遵循非凡作用域规则且可以用作参数的代码块。我将使用 Ruby 来展示闭包的运行原理。用 irb 命令启动解释程序,然后用 load filename 命令加载每个样例。清单 1 是一个最简单的闭包:
3.times {puts "Inside the times method."}Results:Inside the times method.Inside the times method.Inside the times method.
times
是作用在对象 3
上的一个方法。它执行三次闭包中的代码。{puts "Inside the times method."}
是闭包。它是一个匿名函数,times
方法被传递到该函数,函数的结果是打印出静态语句。这段代码比实现相同功能的 for
循环(如清单 2 所示)更加紧凑也更加简单:
for i in 1..3 puts "Inside the times method."end
Ruby 添加到这个简单代码块的第一个扩展是一个参数列表。方法或函数可通过传入参数与闭包通信。在 Ruby 中,使用在 字符之间用逗号隔开的参数列表来表示参数,例如
argument, list
。用这种方法使用参数,可以很轻易地在数据结构(如数组)中构建迭代。清单 3 显示了在 Ruby 中对数组进行迭代的一个例子:
['lions', 'tigers', 'bears'].each {item puts item}Results: lionstigersbears
each
方法用来迭代。您通常想要用执行结果生成一个新的集合。在 Ruby 中,这种方法被称为 collect
。您也许还想在数组的内容里添加一些任意字符串。清单 4 显示了这样的一个例子。这些仅仅是众多使用闭包进行迭代的方法中的两种。
animals = ['lions', 'tigers', 'bears'].collect {item item.upcase}puts animals.join(" and ") + " oh, my."LIONS and TIGERS and BEARS oh, my.
新闻热点
疑难解答