这让我感到惊讶。 在研究了Kotlin语言以了解如何最好地将这种有趣的新语言用于jOOQ之后 ,我偶然发现了这个难题 。 您认为以下程序会打印什么?
fun main(args: Array) {
(1..5).forEach {
if (it == 3)
return
print(it)
}
print("done")
}
好吧……您可能猜错了。 上面将打印:
1 2
它不会打印出大多数人可能期望的内容:
1245done
请注意那些不感到惊讶的人:
上面对于习惯使用Java 8的人来说是特殊的,其中以下代码的确会打印1245done :
public static void main(String[] args) {
IntStream.rangeClosed(1, 5).forEach(it -> {
if (it == 3)
return;
System.out.print(it);
});
System.out.print("done");
}
语法原因在Kotlin手册的以下部分中进行了说明: https : //kotlinlang.org/docs/reference/returns.html
在lambda /闭包中, return语句将不会(必需)从lambda /闭包中返回,而是从lambda /闭包的直接封装范围中返回。 JetBrains的Dmitry Jemerov在两则推文中向我提供了基本原理 :
@lukaseder @kotlin原因很简单:我们希望具有与内置语言功能完全一样的lambda(例如,已同步)
— Dmitry Jemerov(@intelliyole) 2016年2月22日
@lukaseder因此,传递给“同步”功能的lambda中的“返回”必须与Java“同步”块中的“返回”相同
— Dmitry Jemerov(@intelliyole) 2016年2月22日
为Java巧妙的Kotlin语言已经消除基于语言的支持结构,如try-with-resources ,或synchronized语句。 这是非常合理的,因为这些语言构造不一定属于该语言( 正如我们先前在另一篇博客文章中所声称的那样 ),而是可以移至库中。 例如:
// try-with-resources is emulated using an
// extension function "use"
OutputStreamWriter(r.getOutputStream()).use {
it.write('a')
}
- ( 这里的批评 )
要么:
// Synchronized is a function!
val x = synchronized (lock, { computation() })
毕竟,即使在Java中,该语言功能也只能起作用,因为该语言取决于库类型,例如Iterable ( foreach ), AutoCloseable ( try-with-resources )或JVM功能(在每个引用上监控是否要synchronized )
那么,退货有什么关系呢?
按照上述基本原理,当语言设计人员希望避免使用可通过库实现的事物构建语言构造,但仍希望您觉得它们是语言构造时,则在这种“构造”内部return的唯一合理含义-ish” lambda /闭包是从外部范围返回。 因此,当您编写如下内容时:
fun main(args : Array) {
val lock = Object()
val x = synchronized(lock, {
if (1 == 1)
return
"1"
})
print(x)
}
真正的意图是使它等效于以下Java代码:
public static void main(String[] args) {
Object lock = new Object();
String x;
synchronized (lock) {
if (1 == 1)
return;
x = "1";
}
System.out.println(x);
}
显然,在Java情况下, return语句退出main()方法,因为没有其他合理的堆栈框架可从中返回。 与Kotlin不同,在Kotlin中,有人可能会说lambda /闭包将产生自己的堆栈框架。
但这确实不是。 原因是synchronized函数上的inline修饰符:
public inline fun <R> synchronized(lock: Any, block: () -> R): R {
monitorEnter(lock)
try {
return block()
}
finally {
monitorExit(lock)
}
}
这意味着block作为参数传递闭包是不是一个真正的纯lambda表达式,而是嵌入在调用点的范围只是语法糖。
奇怪的。 狡猾。 聪明。 但是有点出乎意料。
这是一个好主意吗? 还是以后语言设计者会后悔? 所有的lambda /闭包是否都可能是“语言构造式的”,而期望这样的return语句会离开外部范围? 还是有明确的例子表明这种inline行为完全有意义?
走着瞧。 在任何情况下,一种语言选择此路径都是非常有趣的。
翻译自: https://www.javacodegeeks.com/2016/02/peculiar-possibly-cunning-kotlin-language-feature.html



所有评论(0)