首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过引用捕获循环中的闭包?

通过引用捕获循环中的闭包?
EN

Stack Overflow用户
提问于 2015-04-20 22:17:10
回答 1查看 174关注 0票数 3

D中的委托似乎通过引用捕获本地值,这在循环中创建闭包时会产生奇怪的副作用:最后,有n个具有相同上下文指针的闭包。举个例子:

代码语言:javascript
复制
import std.stdio;
alias Closure = void delegate();
Closure[] closures;

void main(){
    foreach(a; ["Je", "Tu", "En", "Oui", "Na"])
        closures ~= {write(a);};
    foreach(c; closures)
        c();
    writeln(" batman");
}

这个打印NaNaNaNaNa batman

这是预期的行为吗?如果是这样的话,我将如何绕过它来正确地打印所有数组元素?

当使用带计数器变量的for循环时,它会变得更有趣,最后,i等于数组大小,而在委托中使用closures[i]时,它会抛出一个超出界限的错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-20 23:15:26

是的,这是预期的行为(编辑:...it实际上是一个古老的已知bug!bug.cgi?id=2043,所以只希望它发生,而且您可以很容易地习惯它,但它实际上是不应该发生的),而且在其他语言中也可以看到,所以这是一个很好的了解原则。

若要获得循环中变量的单独副本,请调用返回要存储的委托的另一个函数,将循环变量传递给它。

代码语言:javascript
复制
import std.stdio;
alias Clojure = void delegate();
Clojure[] clojures;

void main(){
    foreach(a; ["Je", "Tu", "En", "Oui", "Na"])
        clojures ~= ((b) => { write(b);})(a);
    foreach(c; clojures)
        c();
    writeln(" batman");
}

clojures ~= ((b) => { write(b);})(a);行已经更改:它定义了返回委托的快速委托。额外的函数返回函数关闭在循环状态的快照上,而不仅仅是函数级局部变量。

我在JavaScript中也经常使用这个:

代码语言:javascript
复制
 function makeHandler(item) {
      return function() {
         // use item here
      };
 }

var array = [1,2,3];
for(var I = 0; I < array.length; I++)
   foo.addEventListener("click", makeHandler(array[I]));

这和D的原因是一样的,只是语法不同,并且分解成更大的函数,而不是像一行代码那样做。

我们定义了一个函数,它返回一个使用捕获的循环变量的函数。在使用点,我们调用一个函数,该函数返回存储给以后使用的委托。

在简写D语法((b) => { write(b);})(a);中,(b) => ...是javascript中看到的makeHandler函数。它返回的{ write(b); }是JS中return function() { ... }的缩写(BTW --相同的JS语法基本上也适用于D,您可以用delegatefunction关键字编写一个长的东西。虽然D的function不捕获变量,但delegate是这样做的)

最后,它周围的括号和最后的(a)只是调用函数。里面的东西和makeHandler是一样的,(...)(a)叫它;它是makeHadndler(a)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29759419

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档