Ausdrücke & Anweisungen
Anweisungen und Ausdrücke sind die kleinsten nützlichen Codefragmente in den meisten Programmiersprachen.
Es gibt einen grundlegenden Unterschied: Eine Anweisung hat eine Wirkung, erzeugt jedoch kein Ergebnis. Ein Ausdruck erzeugt immer ein Ergebnis.
Da eine Anweisung kein Ergebnis erzeugt, muss sie den Zustand ihrer Umgebung ändern, um nützlich zu sein. Anders gesagt: “Eine Anweisung wird wegen ihrer Seiteneffekte aufgerufen” (das heißt, was sie andere als ein Ergebnis zu erzeugen tut). Als Merkhilfe:
Eine Anweisung ändert den Zustand.
Eine Definition von “ausdrücken” ist “herauspressen”, wie in “den Saft aus einer Orange ausdrücken”. Also
Ein Ausdruck drückt aus.
Das heißt, er erzeugt ein Ergebnis.
Die for-Schleife ist eine Anweisung in Kotlin. Sie kann nicht zugewiesen werden, da es kein Ergebnis gibt:
// ExpressionsStatements/ForIsAStatement.kt
fun main() {
// Can't do this:
// val f = for(i in 1..10) {}
// Compiler error message:
// for is not an expression, and
// only expressions are allowed here
}
Eine for-Schleife wird aufgrund ihrer Nebeneffekte verwendet.
Ein Ausdruck erzeugt einen Wert, der zugewiesen oder als Teil eines anderen Ausdrucks verwendet werden kann, während eine Anweisung immer ein Top-Level-Element ist.
Jeder Funktionsaufruf ist ein Ausdruck. Selbst wenn die Funktion Unit zurückgibt und nur aufgrund ihrer Nebeneffekte aufgerufen wird, kann das Ergebnis dennoch zugewiesen werden:
// ExpressionsStatements/UnitReturnType.kt
fun unitFun() = Unit
fun main() {
println(unitFun())
val u1: Unit = println(42)
println(u1)
val u2 = println(0) // Type inference
println(u2)
}
/* Output:
kotlin.Unit
42
kotlin.Unit
0
kotlin.Unit
*/
Der Unit-Typ enthält einen einzelnen Wert namens Unit, den Sie direkt zurückgeben können, wie in unitFun() zu sehen ist. Der Aufruf von println() gibt ebenfalls Unit zurück. Das val u1 erfasst den Rückgabewert von println() und ist explizit als Unit deklariert, während u2 Typinferenz verwendet.
if erzeugt einen Ausdruck, sodass Sie dessen Ergebnis zuweisen können:
// ExpressionsStatements/AssigningAnIf.kt
fun main() {
val result1 = if (11 > 42) 9 else 5
val result2 = if (1 < 2) {
val a = 11
a + 42
} else 42
val result3 =
if ('x' < 'y')
println("x < y")
else
println("x > y")
println(result1)
println(result2)
println(result3)
}
/* Output:
x < y
5
53
kotlin.Unit
*/
Die erste Ausgabelinie ist x < y, obwohl result3 erst am Ende von main() angezeigt wird. Dies geschieht, weil die Auswertung von result3 println() aufruft und die Auswertung erfolgt, wenn result3 definiert wird.
Beachten Sie, dass a innerhalb des Codeblocks für result2 definiert ist. Das Ergebnis des letzten Ausdrucks wird zum Ergebnis des if-Ausdrucks; hier ist es die Summe von 11 und 42. Aber was ist mit a? Sobald Sie den Codeblock verlassen (außerhalb der geschweiften Klammern gehen), können Sie nicht mehr auf a zugreifen. Es ist vorübergehend und wird verworfen, sobald Sie den Gültigkeitsbereich dieses Blocks verlassen.
Der Inkrementoperator i++ ist auch ein Ausdruck, selbst wenn er wie eine Anweisung aussieht. Kotlin folgt dem Ansatz von C-ähnlichen Sprachen und bietet zwei Versionen von Inkrement- und Dekrementoperatoren mit leicht unterschiedlichen Semantiken. Der Präfix-Operator erscheint vor dem Operanden, wie in ++i, und gibt den Wert zurück, nachdem das Inkrement erfolgt ist. Sie können es lesen als “zuerst das Inkrement durchführen, dann den resultierenden Wert zurückgeben”. Der Postfix-Operator wird nach dem Operanden platziert, wie in i++, und gibt den Wert von i zurück, bevor das Inkrement erfolgt. Sie können es lesen als “zuerst das Ergebnis erzeugen, dann das Inkrement durchführen”.
// ExpressionsStatements/PostfixVsPrefix.kt
fun main() {
var i = 10
println(i++)
println(i)
var j = 20
println(++j)
println(j)
}
/* Output:
10
11
21
21
*/
Der Dekrementoperator hat auch zwei Versionen: --i und i--. Die Verwendung von Inkrement- und Dekrementoperatoren innerhalb anderer Ausdrücke wird nicht empfohlen, da dies zu verwirrendem Code führen kann:
// ExpressionsStatements/Confusing.kt
fun main() {
var i = 1
println(i++ + ++i)
}
Versuchen Sie zu erraten, was die Ausgabe sein wird, und überprüfen Sie es dann.
Übungen und Lösungen finden Sie auf www.AtomicKotlin.com.