图没有显示正确的事件字符串

Figure doesn't show correct string on event

在下面的代码中,我用文本 1 到 3 创建了 3 个框,在第四个框中我想显示我的鼠标悬停在框上的文本。所以我为每个框设置了一个 onMouseEnter FProperty,我在其中更改了第四个框的字符串并告诉它重绘。

bool redraw = false;
str s = "0";
Figure getTextbox() {
    return computeFigure(bool() {bool temp = redraw; redraw = false; return temp; },
    Figure() {
        return text(str() {return s; });
    });
}

list[Figure] boxes = [];
for (i <- [1..4]) {
    boxes += box(text(toString(i)), onMouseEnter(void () {s = toString(i); redraw = true; }));
}

Figure changer = box(getTextbox());
render(vcat(boxes + changer));

但是,出于某种奇怪的原因,所有三个框都会告诉 onMouseEnter 方法将第四个框的文本更改为“3”(最后一个框的值)而不是它们各自的值。

知道为什么吗?谢谢!

啊,是的,这是 for 循环的变量捕获闭包问题,也从具有此特定功能的其他语言中知道,例如 Javascript。这是有问题的代码:

for (i <- [1..4]) {
    boxes += box(text(toString(i)), onMouseEnter(void () {s = toString(i); redraw = true; }));
}

变量 i 被 void 闭包绑定,而不是它的值。所以每次创建并传递给 onMouseEnter 的函数都会读取 i 变量的最新值。由于回调是在循环终止后调用的,因此所有对鼠标输入函数的调用都将具有值 3

要解决这个问题 "do what you want",我相信以下代码可以工作:

for (i <- [1..4]) { 
        newS = toString(i);
        boxes += box(text(toString(i)), onMouseEnter(void () {s = newS; redraw = true; }));
    }

这是可行的,因为 for 循环的每一次传递都会创建一个绑定 newS 变量的新环境。所以你会为每个循环得到一个新的 newS 而不是重复使用的 i