我正在学习新的非常漂亮的语言Kotlin,一切似乎都是非常合乎逻辑和一致的。我只发现一件似乎是规则的任意例外而不是一条可靠的规则。但也许我对该规则背后的一些深层原因缺乏足够的了解。
我知道在if-else
和when
语句中有代码块,然后返回最后一个表达式。在下一个示例中,根据条件返回1
或2
- 在我们的示例中,它返回1
。
val x = if (1 < 2) {println("something"); 1} else {println("something else"); 2}
另一方面,这不适用于任何代码块。下一行不会将y
分配给1
,而是将整个代码块分配为lambda。
val y = {println("something"); 1}
同样在函数体中,不返回最后一个表达式。这甚至都没有编译。
fun z() : Int {
println("something")
1
}
那究竟是什么规则?它是否真的如此随意:如果在用作表达式的if-else
或when
语句中有一个代码块,则返回块中的最后一个表达式。否则,最后一个表达式不会返回到外部作用域。或者我错过了什么?
答案 0 :(得分:8)
你误解了大括号I tried
SELECT DATE_ADD( MIN(from_date), interval @num := @num+1 day) AS date_sequence,
tbl_patient.* FROM tbl_patient
HAVING DATE_ADD(MIN(from_date), interval @num day) <= MAX(to_date)
,在使用所有{}
语句时,它只是一个块,例如:
flow-control
WHEN if (condition) { //block here
}
分别声明,它是 lambda 表达式,例如:
{}
WHEN 您希望在val lambda: () -> Int = { 1 }; // lambda
表达式中返回lambda
,您必须将大括号if-else
加倍或使用括号{}
来区分在块和 lambda 表达式之间或明确地将()
设为lambda,例如:
{}
如果函数没有返回任何有用的值,则其返回类型为
val lambda1: () -> Int = if (condition) { { 1 } } else { { 2 } }; val lambda2: () -> Int = if (condition) ({ 1 }) else ({ 2 }); val lambda3: () -> Int = if (condition) { -> 1 } else { -> 2 };
。Unit
是只包含一个值的类型 -Unit
。此值不必返回显式。
另一方面, common Unit
必须有明确的function
语句,如果它的返回类型不是return
:
Unit
另一种情况是函数返回fun z(): Int { return 1; }
,Nothing
语句根本不允许,因为您无法创建return
实例,例如:
Nothing
WHEN 一个函数只有一个表达式,然后您可以改为使用single-expression function,例如:
fun nothing(): Nothing {
return ?;// a compile error raising
}
答案 1 :(得分:2)
lambda块和'normal'块之间存在差异,在您的情况下,“y”只是一个需要执行以获取返回值的lambda:
1.1.2-5
因此,如果你想要一个充当lambda的块,你可以创建一个lambda并立即用“()”执行它。这样,你的“z”函数就会这样编译:
val block: () -> Int = { 5 }
val five: Int = { 5 }()
val anotherFive = block()
(当然,这没有多大意义,效率也不高)
答案 2 :(得分:0)
您绝对正确,V.K。选择是完全任意的。好吧,可能不是完全武断,而是与解析花括号来表示块和lambda引起的复杂性有关。
实际上,除了您要编写块表达式的情况外,还存在(简单)块的情况:只是用括号括起来的一组语句。例如,Java支持(简单)块,您可以编写:
String toBeComputed ; {
// Relatively long sequence of operations here
toBeComputed= resultingValue ;
}
我经常使用这个习语,因为:
有趣的是,由于Java不支持块表达式,因此我将示例编写为
int y ; {
println("something");
y= 1 ;
}
其他语言(我想到了ALGOL和Scala)确实支持块表达式(就Scala而言,它也是lambda,但语法不同)。您用这些语言提出的建议(使用Scala语法)
val y= { println("something"); 1 }
完全有效,不需要()
强制lambda进行评估(因为没有lambda!)。
最后,Kotlin设计师确实选择使语言在块和块表达方面不及ALGOL和Scala一致,这可能是为了方便。
我希望我的长期答复表明,您对Kotlin的期望并非不合逻辑,只是由于某些语言设计选择而并非如此。这次减少惊喜的原则没有用。