Schleifen & Bereiche

Das Schlüsselwort for führt einen Codeblock für jeden Wert in einer Sequenz aus.

Die Menge der Werte kann ein Bereich von Ganzzahlen, ein String oder, wie Sie später im Buch sehen werden, eine Sammlung von Elementen sein. Das Schlüsselwort in zeigt an, dass Sie durch die Werte schreiten:

for (v in values) {
  // Do something with v
}

Jedes Mal, wenn die Schleife durchlaufen wird, erhält v das nächste Element in values.

Hier ist eine for-Schleife, die eine Aktion eine feste Anzahl von Malen wiederholt:

// LoopingAndRanges/RepeatThreeTimes.kt

fun main() {
  for (i in 1..3) {
    println("Hey $i!")
  }
}
/* Output:
Hey 1!
Hey 2!
Hey 3!
*/

Die Ausgabe zeigt, dass der index i jeden Wert im Bereich von 1 bis 3 erhält.

Ein range ist ein Intervall von Werten, das durch ein Paar von Endpunkten definiert wird. Es gibt zwei grundlegende Arten, ranges zu definieren:

// LoopingAndRanges/DefiningRanges.kt

fun main() {
  val range1 = 1..10         // [1]
  val range2 = 0 until 10    // [2]
  println(range1)
  println(range2)
}
/* Output:
1..10
0..9
*/
  • [1] Die Verwendung der ..-Syntax schließt beide Grenzen im resultierenden Bereich ein.
  • [2] until schließt das Ende aus. Die Ausgabe zeigt, dass 10 nicht Teil des Bereichs ist.

Die Anzeige eines Bereichs erzeugt ein lesbares Format.

Dies summiert die Zahlen von 10 bis 100:

// LoopingAndRanges/SumUsingRange.kt

fun main() {
  var sum = 0
  for (n in 10..100) {
    sum += n
  }
  println("sum = $sum")
}
/* Output:
sum = 5005
*/

Sie können über einen Bereich in umgekehrter Reihenfolge iterieren. Sie können auch einen Schritt-Wert verwenden, um das Intervall vom Standardwert 1 zu ändern:

// LoopingAndRanges/ForWithRanges.kt

fun showRange(r: IntProgression) {
  for (i in r) {
    print("$i ")
  }
  print("    // $r")
  println()
}

fun main() {
  showRange(1..5)
  showRange(0 until 5)
  showRange(5 downTo 1)          // [1]
  showRange(0..9 step 2)         // [2]
  showRange(0 until 10 step 3)   // [3]
  showRange(9 downTo 2 step 3)
}
/* Output:
1 2 3 4 5     // 1..5
0 1 2 3 4     // 0..4
5 4 3 2 1     // 5 downTo 1 step 1
0 2 4 6 8     // 0..8 step 2
0 3 6 9     // 0..9 step 3
9 6 3     // 9 downTo 3 step 3
*/
  • [1] downTo erzeugt einen absteigenden Bereich.
  • [2] step ändert das Intervall. Hier wird der Bereich in Schritten von zwei statt einem durchlaufen.
  • [3] until kann auch mit step verwendet werden. Beachten Sie, wie sich dies auf die Ausgabe auswirkt.

In jedem Fall bilden die Zahlenfolgen eine arithmetische Folge. showRange() akzeptiert einen IntProgression-Parameter, der ein eingebauter Typ ist, der Int-Bereiche beinhaltet. Beachten Sie, dass die String-Darstellung jeder IntProgression, wie sie im Ausgabekommentar für jede Zeile erscheint, oft anders ist als der Bereich, der in showRange() übergeben wird—der IntProgression übersetzt die Eingabe in eine gleichwertige gemeinsame Form.

Sie können auch einen Bereich von Zeichen erzeugen. Diese for-Schleife iteriert von a bis z:

// LoopingAndRanges/ForWithCharRange.kt

fun main() {
  for (c in 'a'..'z') {
    print(c)
  }
}
/* Output:
abcdefghijklmnopqrstuvwxyz
*/

Sie können über einen Bereich von Elementen iterieren, die ganze Mengen sind, wie Ganzzahlen und Zeichen, aber nicht Gleitkommawerte.

Eckige Klammern greifen über den Index auf Zeichen zu. Da wir mit dem Zählen der Zeichen in einem String bei Null beginnen, wählt s[0] das erste Zeichen des String s aus. Die Auswahl von s.lastIndex ergibt die letzte Indexnummer:

// LoopingAndRanges/IndexIntoString.kt

fun main() {
  val s = "abc"
  for (i in 0..s.lastIndex) {
    print(s[i] + 1)
  }
}
/* Output:
bcd
*/

Manchmal beschreiben Leute s[0] als “das nullte Zeichen.”

Zeichen werden als Zahlen gespeichert, die ihren Unicode-Werten entsprechen. Daher ergibt das Hinzufügen einer Ganzzahl zu einem Zeichen ein neues Zeichen, das dem neuen Codewert entspricht:

// LoopingAndRanges/AddingIntToChar.kt

fun main() {
  val ch: Char = 'a'
  println(ch + 25)
  println(ch < 'z')
}
/* Output:
z
true
*/

Die zweite println() zeigt, dass man Zeichencodes vergleichen kann.

Eine for-Schleife kann direkt über Strings iterieren:

// LoopingAndRanges/IterateOverString.kt

fun main() {
  for (ch in "Jnskhm ") {
    print(ch + 1)
  }
}
/* Output:
Kotlin!
*/

ch empfängt nacheinander jedes Zeichen.

Im folgenden Beispiel durchläuft die Funktion hasChar() den String s und prüft, ob er ein bestimmtes Zeichen ch enthält. Das return in der Mitte der Funktion stoppt die Funktion, sobald die Antwort gefunden wird:

// LoopingAndRanges/HasChar.kt

fun hasChar(s: String, ch: Char): Boolean {
  for (c in s) {
    if (c == ch) return true
  }
  return false
}

fun main() {
  println(hasChar("kotlin", 't'))
  println(hasChar("kotlin", 'a'))
}
/* Output:
true
false
*/

Das nächste Atom zeigt, dass hasChar() unnötig ist — Sie können stattdessen die eingebaute Syntax verwenden.

Wenn Sie einfach eine Aktion eine feste Anzahl von Malen wiederholen möchten, können Sie repeat() anstelle einer for-Schleife verwenden:

// LoopingAndRanges/RepeatHi.kt

fun main() {
  repeat(2) {
    println("hi!")
  }
}
/* Output:
hi!
hi!
*/

repeat() ist eine Standardbibliotheksfunktion, kein Schlüsselwort. Sie werden viel später im Buch sehen, wie sie erstellt wurde.

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