返回块中的最后一个表达式

时间:2017-06-14 06:34:33

标签: kotlin

我正在学习新的非常漂亮的语言Kotlin,一切似乎都是非常合乎逻辑和一致的。我只发现一件似乎是规则的任意例外而不是一条可靠的规则。但也许我对该规则背后的一些深层原因缺乏足够的了解。

我知道在if-elsewhen语句中有代码块,然后返回最后一个表达式。在下一个示例中,根据条件返回12 - 在我们的示例中,它返回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-elsewhen语句中有一个代码块,则返回块中的最后一个表达式。否则,最后一个表达式不会返回到外部作用域。或者我错过了什么?

3 个答案:

答案 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的期望并非不合逻辑,只是由于某些语言设计选择而并非如此。这次减少惊喜的原则没有用。