注意:如果您只想跳过上下文,请跳至下面的“问题”
在谈论Scala时,我几乎总是确定我会被问到“但你什么时候会使用Closure?”通常我会说“等到我向你展示一个理解”,然后我会展示如何将这种理解归结为使用flatMap / map +闭包。
这个例子确实有帮助,但是我很难解释一般情况“这是你知道何时使用闭包的时候”。这是你在函数式编程中“习惯”的事情之一,你几乎不用思考就可以了。
当我谈到Scala时,通常我正在与Java开发人员交谈,而且我想到的一个类比是“你知道当你创建一个匿名的内部类,需要访问某个位于定义类之上的变量吗?那是像一个封闭“。所以我使用事件回调处理作为一个特例(在这种情况下你不可避免地使用匿名内部类)。
考虑到观众(没有经验,或者对FP的经验有限),我不会继续讨论像Monads这样的术语,这些人通常会寻找他们可以联系到的具体/实用的例子。
问题: 任何人都有自己的方式来成功解释真正适合Java(或其他OO语言)开发人员的闭包吗?
答案 0 :(得分:9)
许多Java开发人员已经熟悉'closures-lite' - 模仿用类封闭的设计模式:
每当Java开发人员使用其中一种模式来解决Scala中的问题时,他们应该将闭包视为轻量级替代方案。
正如你所提到的,第一类闭包在某些方面只是这些模式的逻辑扩展 - 如果我的匿名类只有一个方法,为什么不完全取消该类,并且只是拥有该方法呢?
讨论所有这些模式的共同点也是值得的 - 它们都是某种形式的控制流抽象。它们将控制流本身与在该流程中的某些点处执行的动作分开。任何类似的关注点分离都可以从关闭中受益。
答案 1 :(得分:6)
为什么不颠倒演示顺序?当您通常呈现闭包时,呈现一个众所周知的模式(如听众或访客)。然后展示Closures如何在不创建额外的“帮助”对象或不必要的代码框架工作的情况下解决问题。
您说您的受众正在寻找Closures如何工作的具体示例。在展示其中的一些之后,您可以后退并正确定义闭合。提出问题,解决问题,再次解决问题,再次解决问题,然后提出更大理论的技术对程序员来说并不陌生。这就是他们首先发现模式的方式。
答案 2 :(得分:1)
为了将这个概念引入Java开发人员,我认为你正确地将闭包与匿名内部类相关联。我建议采取一些涉及大量使用回调的问题,并展示一张幻灯片,其中使用匿名内部类和Scala中使用闭包所需的代码对Java所需的代码进行并排比较。
以下是涉及回调问题的几点想法:
对于这些示例中的每一个,我希望Scala / closure解决方案比Java /匿名内部类解决方案更短更简单。
答案 3 :(得分:1)
如果您的意思是匿名函数,而不仅仅是闭包,我通常使用以下示例。给出一个简单的集合(在本例中是一个名称列表),并显示使用匿名函数查询和修改的简单程度。
Java - 获取以“A”开头的新名称列表:
List<String> names = Arrays.asList("Ed", "Bob", "Anna");
List<String> namesOnA = new ArrayList<String>();
for(String name : names) {
if(name.startsWith("A")) {
namesOnA.add(name);
}
}
Scala - 获取以“A”开头的名称列表:
val names = List("Ed", "Bob", "Anna")
val namesOnA = names.filter(_.startsWith("A"))
在集合上使用map,reduceLeft和其他方法的类似示例。大多数Java开发人员都觉得这很有趣。
答案 4 :(得分:1)
您要求对源自不存在或很少使用的语言的开发人员的闭包进行简单解释。
这是一个简洁的解释,将它们比作函数返回时未解除分配的堆栈帧:"JavaScript Closures 101- they're not magic"。我觉得这对于一个与这个想法挣扎的传统开发者来说是一个有用的概念。
此外,Java封闭辩论早期的Goslings upvote of them将引起Java开发人员的兴趣。请注意,他还引用Neal Gafter's original proposal将其包含在Java中。