2

今天我在将一些 java 代码移植到 groovy 时发现了一些 groovy 的严重行为。

我们在 java 中一直在做的事情:在循环中构建匿名类(例如用于操作)并引用在该类之外声明的最终变量。

如果让你在 groovy 中运行这段代码,你得到的不是 1,2,3,4,5,6,7,8,9,而是 9,9,9,9,9,9,9, 9,9。这意味着 groovy 不会将各自的最终变量 i 绑定到每个匿名类,而只是使用执行时的最后一个设置值。

我在 groovy 文档中找不到这种行为的任何原因。顺便说一句,如果我使用 groovy 闭包而不是匿名类,我会得到相同的行为。

public static void main(String[] args) {
    int[] list = new int[10];
    for (int i = 0; i < 10; i++) {
        list[i] = i;
    }
    Runnable[] runnables = new Runnable[10];
    for (final int i : list) {
        runnables[i] = new Runnable() {
            @Override
            public void run() {
                System.out.println(i);
            }
        };
    }

    for (int i = 0; i < 10; i++) {
        runnables[i].run();
    }
}
4

2 回答 2

3

奇怪...我会调查一下这是否是已知行为

同时,您可以通过在生成可运行文件的循环内声明另一个变量来解决它,然后在您的可运行文件中使用它:

for (int i : list) {
    int k = i
    runnables[i] = new Runnable() {
        @Override
        public void run() {
            System.out.println(k);
        }
    }
}

或者通过使用生成 Runnable 数组collect

Runnable[] runnables = list.collect { i -> 
    new Runnable() {
        @Override
        public void run() {
            System.out.println( i );
        }
    }
}

编辑

我已经四处询问,并且在类属性之外,finalGroovy 目前忽略了它。这是将来可能添加的东西

于 2013-07-04T09:47:03.080 回答
0

我相信问题出在for循环上。简化代码:

def runnables = []
for (int i: 0..9) {
    runnables << {
        println i
    }
}
runnables*.call() // prints 9, 9, 9, 9, 9, 9, 9, 9, 9, 9

有趣的是,传统的for循环输出全部 10:

def runnables = []
for (int i = 0; i < 10; ++i) {
    runnables << {
        println i
    }
}
runnables*.call() // prints 10, 10, 10, 10, 10, 10, 10, 10, 10, 10

使用范围代替for循环将按预期工作:

def runnables = []
(0..9).each { i ->
    runnables << {
        println i
    }
}
runnables*.call() // prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

i所以是的,当调用闭包(或匿名 Runnable)时,它会在已经执行的循环范围内查找对 from 的引用for,此时 的值i是其完全递增的值。我不确定这是否是故意的。

于 2013-07-07T22:19:43.480 回答