你如何让foreach为代表使用非引用类型?

kos*_*hei 4 foreach delegates d pass-by-reference

产生问题的示例代码:

import std.stdio, core.thread;
void main() {
    ThreadGroup tg = new ThreadGroup();
    foreach (int i; 1 .. 5)
        tg.create( () => writeln(i) );
    tg.joinAll();
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

3
5
5
5
5
Run Code Online (Sandbox Code Playgroud)

(预期输出为整数1到5)

我不明白为什么会发生这种情况 - i不是引用类型,也没有引用它在委托中使用,所以为什么每个线程使用的值i作为线程所在的任何值预定的,而不是它给出的大概传值值?

我做了一些这样的蹩脚尝试,但没有成功:

foreach (int i; 1 .. 5) {
    scope j = i;
    tg.create( () => writeln(j) );
}
Run Code Online (Sandbox Code Playgroud)

我很好奇为什么这不起作用.是不是j每次都宣布新鲜的?为什么每个线程引用相同的j(在线程调度时它的值通常为5)?

Vla*_*eev 6

那么为什么每个线程使用i的值作为调度线程时它碰巧具有的值,而不是它给出的大概传值值?

就循环体而言,它是pass-by-value,但是这不适用于在其中创建的线程.线程仍将i通过其地址引用.

要解决此问题,您需要在循环内创建一个闭包:

import std.stdio, core.thread;
void main() {
    ThreadGroup tg = new ThreadGroup();
    foreach (int i; 1 .. 5)
        (i =>
            tg.create( () => writeln(i) )
        )(i);
    tg.joinAll();
}
Run Code Online (Sandbox Code Playgroud)

lambda参数将存储在闭包中,为每个线程提供自己的副本.