Zusammenfassung 1

Dieses Atom fasst die Atome in Abschnitt I zusammen und überprüft sie, beginnend bei Hallo, Welt! und endend mit Ausdrücke & Anweisungen.

Wenn Sie ein erfahrener Programmierer sind, sollte dies Ihr erstes Atom sein. Neue Programmierer sollten dieses Atom lesen und die Übungen als Überprüfung von Abschnitt I durchführen.

Wenn Ihnen etwas unklar ist, studieren Sie das zugehörige Atom zu diesem Thema (die Unterüberschriften entsprechen den Atomtiteln).

Hallo, Welt

Kotlin unterstützt sowohl // Einzelzeilenkommentare als auch /*-bis-*/ Mehrzeilenkommentare. Der Einstiegspunkt eines Programms ist die Funktion main():

// Summary1/Hello.kt

fun main() {
  println("Hello, world!")
}
/* Output:
Hello, world!
*/

Die erste Zeile jedes Beispiels in diesem Buch ist ein Kommentar, der den Namen des Unterverzeichnisses des Atoms enthält, gefolgt von einem / und dem Dateinamen. Alle extrahierten Code-Beispiele finden Sie unter AtomicKotlin.com.

println() ist eine Standardbibliotheksfunktion, die einen einzelnen String-Parameter (oder einen Parameter, der in einen String konvertiert werden kann) nimmt. println() bewegt den Cursor nach der Ausgabe seines Parameters in eine neue Zeile, während print() den Cursor in derselben Zeile lässt.

Kotlin erfordert kein Semikolon am Ende eines Ausdrucks oder einer Anweisung. Semikolons sind nur notwendig, um mehrere Ausdrücke oder Anweisungen in einer einzigen Zeile zu trennen.

var & val, Datentypen

Um einen unveränderlichen Bezeichner zu erstellen, verwenden Sie das Schlüsselwort val, gefolgt vom Bezeichnernamen, einem Doppelpunkt und dem Typ für diesen Wert. Fügen Sie dann ein Gleichheitszeichen und den Wert hinzu, der diesem val zugewiesen werden soll:

val identifier: Type = initialization

Sobald einem val ein Wert zugewiesen wurde, kann er nicht neu zugewiesen werden.

Kotlons Typinferenz kann normalerweise den Typ automatisch bestimmen, basierend auf dem Initialisierungswert. Dies führt zu einer einfacheren Definition:

val identifier = initialization

Beide der folgenden sind gültig:

val daysInFebruary = 28
val daysInMarch: Int = 31

Eine var (Variable) Definition sieht gleich aus, indem var anstelle von val verwendet wird:

var identifier1 = initialization
var identifier2: Type = initialization

Im Gegensatz zu einem val können Sie ein var ändern, daher ist Folgendes zulässig:

var hoursSpent = 20
hoursSpent = 25

Allerdings kann der Typ nicht geändert werden, sodass Sie einen Fehler erhalten, wenn Sie sagen:

hoursSpent = 30.5

Kotlin leitet den Int-Typ ab, wenn hoursSpent definiert wird, daher wird es die Änderung in einen Gleitkommawert nicht akzeptieren.

Funktionen

Funktionen sind benannte Unterprogramme:

fun functionName(arg1: Type1, arg2: Type2, ...): ReturnType {
  // Lines of code ...
  return result
}

Das Schlüsselwort fun wird gefolgt vom Funktionsnamen und der Parameterliste in Klammern. Jeder Parameter muss einen expliziten Typ haben, da Kotlin die Parameterarten nicht ableiten kann. Die Funktion selbst hat einen Typ, der auf die gleiche Weise definiert wird wie bei var oder val (ein Doppelpunkt gefolgt vom Typ). Der Typ der Funktion ist der Typ des zurückgegebenen Ergebnisses.

Die Funktionssignatur wird gefolgt vom Funktionskörper, der in geschweiften Klammern enthalten ist. Die return-Anweisung liefert den Rückgabewert der Funktion.

Sie können eine abgekürzte Syntax verwenden, wenn die Funktion aus einem einzelnen Ausdruck besteht:

fun functionName(arg1: Type1, arg2: Type2, ...): ReturnType = result

Diese Form wird als Ausdruckskörper bezeichnet. Anstelle einer öffnenden geschweiften Klammer verwenden Sie ein Gleichheitszeichen gefolgt vom Ausdruck. Sie können den Rückgabetyp weglassen, weil Kotlin ihn ableitet.

Hier ist eine Funktion, die den Würfel ihres Parameters produziert, und eine andere, die ein Ausrufezeichen zu einem String hinzufügt:

// Summary1/BasicFunctions.kt

fun cube(x: Int): Int {
  return x * x * x
}

fun bang(s: String) = s + "!"

fun main() {
  println(cube(3))
  println(bang("pop"))
}
/* Output:
27
pop!
*/

cube() hat einen Blockkörper mit einer expliziten return-Anweisung. bang() ist ein Ausdruckskörper, der den Rückgabewert der Funktion erzeugt. Kotlin leitet den Rückgabetyp von bang() als String ab.

Boolesche Werte

Für die Boolesche Algebra bietet Kotlin Operatoren wie:

  • ! (nicht) negiert den Wert logisch (wandelt true in false und umgekehrt).
  • && (und) gibt true nur zurück, wenn beide Bedingungen true sind.
  • || (oder) gibt true zurück, wenn mindestens eine der Bedingungen true ist.
// Summary1/Booleans.kt

fun main() {
  val opens = 9
  val closes = 20
  println("Operating hours: $opens - $closes")
  val hour = 6
  println("Current time: " + hour)

  val isOpen = hour >= opens && hour < closes
  println("Open: " + isOpen)
  println("Not open: " + !isOpen)

  val isClosed = hour < opens || hour >= closes
  println("Closed: " + isClosed)
}
/* Output:
Operating hours: 9 - 20
Current time: 6
Open: false
Not open: true
Closed: true
*/

Der Initialisierer von isOpen verwendet &&, um zu testen, ob beide Bedingungen true sind. Die erste Bedingung hour >= opens ist false, sodass das Ergebnis des gesamten Ausdrucks false wird. Der Initialisierer für isClosed verwendet ||, was true ergibt, wenn mindestens eine der Bedingungen true ist. Der Ausdruck hour < opens ist true, daher ist der gesamte Ausdruck true.

if-Ausdrücke

Da if ein Ausdruck ist, liefert es ein Ergebnis. Dieses Ergebnis kann einer var oder val zugewiesen werden. Hier sehen Sie auch die Verwendung des Schlüsselworts else:

// Summary1/IfResult.kt

fun main() {
  val result = if (99 < 100) 4 else 42
  println(result)
}
/* Output:
4
*/

Entweder Zweig eines if-Ausdrucks kann ein mehrzeiliger Codeblock sein, der von geschweiften Klammern umgeben ist:

// Summary1/IfExpression.kt

fun main() {
  val activity = "swimming"
  val hour = 10

  val isOpen = if (
    activity == "swimming" ||
    activity == "ice skating") {
    val opens = 9
    val closes = 20
    println("Operating hours: " +
      opens + " - " + closes)
    hour >= opens && hour < closes
  } else {
    false
  }
  println(isOpen)
}
/* Output:
Operating hours: 9 - 20
true
*/

Ein Wert, der innerhalb eines Codeblocks definiert ist, wie opens, ist außerhalb des Gültigkeitsbereichs dieses Blocks nicht zugänglich. Da sie global für den if-Ausdruck definiert sind, sind activity und hour innerhalb des if-Ausdrucks zugänglich.

Das Ergebnis eines if-Ausdrucks ist das Ergebnis des letzten Ausdrucks des gewählten Zweigs. Hier ist es hour >= opens && hour <= closes, was true ist.

String-Vorlagen

Sie können einen Wert innerhalb eines String mit Hilfe von String-Vorlagen einfügen. Verwenden Sie ein $ vor dem Bezeichnernamen:

// Summary1/StrTemplates.kt

fun main() {
  val answer = 42
  println("Found $answer!")            // [1]
  val condition = true
  println(
    "${if (condition) 'a' else 'b'}")  // [2]
  println("printing a $1")             // [3]
}
/* Output:
Found 42!
a
printing a $1
*/
  • [1] $answer ersetzt den Wert, der in answer enthalten ist.
  • [2] ${if(condition) 'a' else 'b'} wertet den Ausdruck innerhalb von ${} aus und ersetzt das Ergebnis.
  • [3] Wenn dem $ etwas folgt, das nicht als Programmkennzeichner erkennbar ist, passiert nichts Besonderes.

Verwenden Sie dreifach-angeführte Strings, um mehrzeiligen Text oder Text mit Sonderzeichen zu speichern:

// Summary1/ThreeQuotes.kt

fun json(q: String, a: Int) = """{
  "question" : "$q",
  "answer" : $a
}"""

fun main() {
  println(json("The Ultimate", 42))
}
/* Output:
{
  "question" : "The Ultimate",
  "answer" : 42
}
*/

Sie müssen keine Sonderzeichen wie " innerhalb eines dreifach-umrahmten String maskieren. (In einem regulären String schreiben Sie \", um ein Anführungszeichen einzufügen). Wie bei normalen Strings können Sie einen Bezeichner oder einen Ausdruck mit $ innerhalb eines dreifach-umrahmten String einfügen.

Zahlentypen

Kotlin bietet Ganzzahltypen (Int, Long) und Fließkommatypen (Double). Eine Ganzzahlenkonstante ist standardmäßig Int und Long, wenn Sie ein L anhängen. Eine Konstante ist Double, wenn sie einen Dezimalpunkt enthält:

// Summary1/NumberTypes.kt

fun main() {
  val n = 1000    // Int
  val l = 1000L   // Long
  val d = 1000.0  // Double
  println("$n $l $d")
}
/* Output:
1000 1000 1000.0
*/

Ein Int hält Werte zwischen -231 und +231-1. Ganzzahlenwerte können einen Überlauf verursachen; zum Beispiel verursacht das Hinzufügen von irgendetwas zu Int.MAX_VALUE einen Überlauf:

// Summary1/Overflow.kt

fun main() {
  println(Int.MAX_VALUE + 1)
  println(Int.MAX_VALUE + 1L)
}
/* Output:
-2147483648
2147483648
*/

Im zweiten println()-Statement fügen wir L zu 1 hinzu, wodurch der gesamte Ausdruck vom Typ Long wird, was den Überlauf verhindert. (Ein Long kann Werte zwischen -263 und +263-1 aufnehmen).

Wenn Sie ein Int durch ein anderes Int teilen, erzeugt Kotlin ein Int-Ergebnis, und ein verbleibender Rest wird abgeschnitten. Also ergibt 1/2 0. Wenn ein Double beteiligt ist, wird das Int vor der Operation zu Double hochgestuft, sodass 1.0/2 0.5 ergibt.

Man könnte erwarten, dass d1 im Folgenden 3.4 ergibt:

// Summary1/Truncation.kt

fun main() {
  val d1: Double = 3.0 + 2 / 5
  println(d1)
  val d2: Double = 3 + 2.0 / 5
  println(d2)
}
/* Output:
3.0
3.4
*/

Aufgrund der Auswertungsreihenfolge tut es das nicht. Kotlin teilt zuerst 2 durch 5, und Ganzzahlmathematik ergibt 0, was zu einem Ergebnis von 3.0 führt. Dieselbe Auswertungsreihenfolge erzeugt das erwartete Ergebnis für d2. Die Division von 2.0 durch 5 ergibt 0.4. Die 3 wird zu einem Double hochgestuft, weil wir es zu einem Double (0.4) addieren, was 3.4 ergibt.

Das Verständnis der Auswertungsreihenfolge hilft Ihnen zu entschlüsseln, was ein Programm macht, sowohl mit logischen Operationen (Boolean-Ausdrücken) als auch mit mathematischen Operationen. Wenn Sie sich über die Auswertungsreihenfolge unsicher sind, verwenden Sie Klammern, um Ihre Absicht zu erzwingen. Dies macht es auch für diejenigen, die Ihren Code lesen, klar.

Wiederholung mit while

Eine while-Schleife läuft weiter, solange der kontrollierende Boolean-Ausdruck true ergibt:

while (Boolean-expression) {
  // Code to be repeated
}

Der Boolean expression wird einmal zu Beginn der Schleife und erneut vor jeder weiteren Iteration ausgewertet.

// Summary1/While.kt

fun testCondition(i: Int) = i < 100

fun main() {
  var i = 0
  while (testCondition(i)) {
    print(".")
    i += 10
  }
}
/* Output:
..........
*/

Kotlin leitet Boolean als Ergebnistyp für testCondition() ab.

Die Kurzformen der Zuweisungsoperatoren sind für alle mathematischen Operationen verfügbar (+=, -=, *=, /=, %=). Kotlin unterstützt auch die Inkrement- und Dekrementoperatoren ++ und --, sowohl in Präfix- als auch in Postfix-Form.

while kann mit dem Schlüsselwort do verwendet werden:

do {
  // Code to be repeated
} while (Boolean-expression)

Umschreiben von While.kt:

// Summary1/DoWhile.kt

fun main() {
  var i = 0
  do {
    print(".")
    i += 10
  } while (testCondition(i))
}
/* Output:
..........
*/

Der einzige Unterschied zwischen while und do-while besteht darin, dass der Körper von do-while immer mindestens einmal ausgeführt wird, selbst wenn der boolesche Ausdruck beim ersten Mal false ergibt.

Schleifen & Bereiche

Viele Programmiersprachen greifen auf ein iterierbares Objekt zu, indem sie durch ganze Zahlen gehen. Kotlins for erlaubt es Ihnen, Elemente direkt aus iterierbaren Objekten wie Bereichen und Strings zu entnehmen. Zum Beispiel wählt diese for-Schleife jedes Zeichen in der Zeichenkette "Kotlin" aus:

// Summary1/StringIteration.kt

fun main() {
  for (c in "Kotlin") {
    print("$c ")
    // c += 1 // error:
    // val cannot be reassigned
  }
}
/* Output:
K o t l i n
*/

c kann nicht explizit als entweder var oder val definiert werden—Kotlin macht es automatisch zu einem val und leitet seinen Typ als Char ab (man kann den Typ explizit angeben, aber in der Praxis wird dies selten getan).

Sie können durch ganze Zahlenwerte mit Bereichen iterieren:

// Summary1/RangeOfInt.kt

fun main() {
  for (i in 1..10) {
    print("$i ")
  }
}
/* Output:
1 2 3 4 5 6 7 8 9 10
*/

Einen Bereich mit .. zu erstellen, schließt beide Grenzen ein, aber until schließt das obere Ende aus: 1 bis 10 ist dasselbe wie 1..9. Sie können einen Inkrementwert mit step angeben: 1..21 Schritt 3.

Das in Schlüsselwort

Dasselbe in, das die Iteration in for Schleifen ermöglicht, erlaubt es Ihnen auch, die Zugehörigkeit zu einem Bereich zu überprüfen. !in gibt true zurück, wenn der getestete Wert nicht im Bereich liegt:

// Summary1/Membership.kt

fun inNumRange(n: Int) = n in 50..100

fun notLowerCase(ch: Char) = ch !in 'a'..'z'

fun main() {
  val i1 = 11
  val i2 = 100
  val c1 = 'K'
  val c2 = 'k'
  println("$i1 ${inNumRange(i1)}")
  println("$i2 ${inNumRange(i2)}")
  println("$c1 ${notLowerCase(c1)}")
  println("$c2 ${notLowerCase(c2)}")
}
/* Output:
11 false
100 true
K true
k false
*/

in kann auch verwendet werden, um die Zugehörigkeit zu Gleitkomma-Bereichen zu testen, obwohl solche Bereiche nur mit .. und nicht mit until definiert werden können.

Ausdrücke & Statements

Das kleinste nützliche Codefragment in den meisten Programmiersprachen ist entweder ein Statement oder ein Ausdruck. Diese haben einen grundlegenden Unterschied:

  • Ein Statement ändert den Zustand.
  • Ein Ausdruck drückt aus.

Das heißt, ein Ausdruck liefert ein Ergebnis, während ein Statement das nicht tut. Weil es nichts zurückgibt, muss ein Statement den Zustand seiner Umgebung ändern (das heißt, einen Seiteneffekt erzeugen), um etwas Nützliches zu tun.

Fast alles in Kotlin ist ein Ausdruck:

val hours = 10
val minutesPerHour = 60
val minutes = hours * minutesPerHour

In jedem Fall ist alles rechts vom = ein Ausdruck, der ein Ergebnis liefert, das der Bezeichnung links zugewiesen wird.

Funktionen wie println() scheinen kein Ergebnis zu erzeugen, aber da sie immer noch Ausdrücke sind, müssen sie etwas zurückgeben. Kotlin hat dafür einen speziellen Typ namens Unit:

// Summary1/UnitReturn.kt

fun main() {
  val result = println("returns Unit")
  println(result)
}
/* Output:
returns Unit
kotlin.Unit
*/

Erfahrene Programmierer sollten nach dem Bearbeiten der Übungen für dieses Atom zu Zusammenfassung 2 gehen.

Übungen und Lösungen finden Sie unter www.AtomicKotlin.com.