【发布时间】:2017-07-21 17:15:18
【问题描述】:
我们知道 lambda 主体是惰性的,因为如果我们不调用 lambda,则永远不会调用 lambda 主体中的代码。
我们还知道在任何函数语言中,即使没有初始化变量也可以在函数/lambda中使用,例如javascript、ruby、groovy和.etc,例如,下面的groovy代码可以正常工作:
def foo
def lambda = { foo }
foo = "bar"
println(lambda())
// ^--- return "bar"
我们还知道,如果在 Java 中的 try-block 中引发 Exception 时 catch-block 已经初始化了变量,我们可以访问未初始化的变量,例如:
// v--- m is not initialized yet
int m;
try{ throw new RuntimeException(); } catch(Exception ex){ m = 2;}
System.out.println(m);// println 2
如果 lambda 是惰性的,为什么 Kotlin 不能在 lambda 中使用未初始化的变量?我知道 Kotlin 是一种空安全语言,因此编译器会从上到下分析代码,包括 lambda 主体,以确保变量已初始化。所以 lambda 主体在编译时不是“懒惰”的。例如:
var a:Int
val lambda = { a }// lambda is never be invoked
// ^--- a compile error thrown: variable is not initialized yet
a = 2
问:但是为什么下面的代码也不能工作?我不明白,因为变量在 Java 中是有效最终,如果你想更改变量值,你必须使用ObjectRef,而这个测试与我之前的结论相矛盾:" lambda body 在编译时并不懒惰”。例如:
var a:Int
run{ a = 2 }// a is initialized & inlined to callsite function
// v--- a compile error thrown: variable is not initialized yet
println(a)
所以我只能认为编译器无法确定ObjectRef 中的element 字段是否已初始化,但@hotkey 否认了我的想法。 为什么?
问:为什么 Kotlin 内联函数不能正常工作,即使我像在 java 中一样在 catch-block 中初始化变量?例如:
var a: Int
try {
run { a = 2 }
} catch(ex: Throwable) {
a = 3
}
// v--- Error: `a` is not initialized
println(a)
但是,@hotkey 已经提到你应该在 Kotlin 中使用 try-catch 表达式来初始化 his answer 中的变量,例如:
var a: Int = try {
run { 2 }
} catch(ex: Throwable) {
3
}
// v--- println 2
println(a);
问:如果真的是这样,我为什么不直接打电话给run?例如:
val a = run{2};
println(a);//println 2
但是上面的代码在java中可以正常工作,例如:
int a;
try {
a = 2;
} catch (Throwable ex) {
a = 3;
}
System.out.println(a); // println 2
【问题讨论】:
标签: variables lambda functional-programming kotlin