我在 Groovy3 中做了一些测试,Java lambda 表达式大多被解释为闭包而不是功能接口实例。 如何使 lambda 以实用的方式(无强制)与泛型一起使用以及 Groovy4 相比如何?
@CompileStatic
// lambda (ok!)
Supplier<String> s = 5::toString
// decompiled
Supplier s = DefaultGroovyMethods::toString;
// closure (wth?)
Supplier<String> s
s = 5::toString
// decompiled
Supplier s = null;
Closure var3 = ScriptBytecodeAdapter.getMethodPointer(5, "toString");
s = (Supplier)ScriptBytecodeAdapter.castToType(var3, Supplier.class);
// lambda
void test(Supplier<String> s) {}
test(5::toString)
// decompiled
test(DefaultGroovyMethods::toString);
// fails with "Groovyc: The argument is a method reference,
// but the parameter type is not a functional interface"
<T> void test(T s) {}
this.<Supplier<String>>test(5::toString)
// closure (fails without coercion)
List<Supplier<String>> list = [5::toString]
// lambda (works, but cumbersome)
Supplier<String> s = 5::toString
List<Supplier<String>> list = [s]
// closure (fails without coercion)
List<Supplier<String>> list = []
list.add(5::toString)
我希望静态编译的 Java lambda 语法始终强制执行 Java lambda 语义。
Lambda 和方法引用是 Groovy 3 的新功能。考虑到这一点,静态编译 (
@CompileStatic
) 的目标是像 Java 一样工作。然而,有一些边缘情况作为错误出现并自 Groovy 3.0.0 以来已得到修复,而另一些则尚未修复。您已经遇到了其中一些边缘情况。
当 Groovy 无法检测到 lambda 或方法引用表达式的目标是函数式接口时,它会分别依靠闭包或方法指针处理。这就是为什么您会在拆分声明中看到“ScriptBytecodeAdapter.getMethodPointer”。
我有一个 bug 修复,该修复将进入 Groovy 3.0.22 中的 split 声明(请参阅 GROOVY-11363)。这种情况应该已经在 Groovy 4 中得到正确处理(正如您所期望的)。
请使用最新的 Groovy 5 alpha 版本(目前是我们的主分支)尝试上述每种情况,如果您发现任何内容无法按预期工作,请在此处开具新票证:https://issues .apache.org/jira/projects/GROOVY