Zum Inhalt springen

Schleifen in Rust

Rust kennt drei Arten, Code zu wiederholen: loop, while und for. Auf dieser Seite geht es um loop, die einfachste und direkteste der drei Schleifen. Sie wiederholt sich endlos, bis du ihr sagst, dass sie aufhören soll.

fn main() {
let mut count = 0;
loop {
count += 1;
println!("{count}");
if count == 3 {
break;
}
}
}

Ausgabe:

1
2
3
▶ Selbst ausprobieren

Von allein hört loop nie auf – erst break beendet die Schleife. Ohne das if count == 3 { break; } würde dieses Programm endlos weiterzählen.

Das hier kann loop, aber nicht while und for: Du kannst hinter break einen Wert schreiben. Dieser Wert wird dann zum Ergebnis der ganzen Schleife:

fn main() {
let mut count = 0;
let result = loop {
count += 1;
if count == 10 {
break count * 2; // anhalten und einen Wert zurückgeben
}
};
println!("{result}");
}

Ausgabe:

20
▶ Selbst ausprobieren

Das ist praktisch für Fälle wie „Versuch es so lange, bis es klappt, und gib mir dann das Ergebnis“. Dieses Muster begegnet dir in echtem Code öfter, als du denkst.

Achte auf das Semikolon nach der schließenden } der Schleife. Die ganze loop { ... } ist die rechte Seite von let result = ...;. Deshalb braucht die let-Anweisung am Ende ihr ; – genau wie bei let x = 5;.

Wenn du aus einer anderen Sprache kommst, schreibst du eine Endlosschleife vielleicht als while true { ... }. Das funktioniert in Rust, aber der Compiler warnt dich:

warning: denote infinite loops with `loop { ... }`
--> src/main.rs:5:5
|
5 | while true {
| ^^^^^^^^^^ help: use `loop`

Die Warnung sagt: Kennzeichne Endlosschleifen mit loop { ... }. Dabei geht es nicht nur um Stil. Rust weiß, dass der Rumpf einer loop immer läuft und dass sie nur über ein break verlassen werden kann. Bei while true nimmt Rust das nicht an, weil es sich den Wert der Bedingung nicht anschaut. Das macht einen echten Unterschied, wenn eine Variable ihren Wert erst in der Schleife bekommt:

fn main() {
let mut n = 1;
let answer; // noch kein Wert
loop {
if n * n > 50 {
answer = n * n; // direkt vor dem Verlassen setzen
break;
}
n += 1;
}
println!("Die erste Quadratzahl über 50 ist {answer}");
}

Ausgabe:

Die erste Quadratzahl über 50 ist 64
▶ Selbst ausprobieren

Mit loop erkennt Rust, dass println! nur über dieses break erreicht werden kann. answer ist also immer gesetzt. Ersetzt du loop durch while true, bekommst du error[E0381]: used binding answer is possibly-uninitialized – die Variable ist möglicherweise nicht initialisiert. Der Compiler glaubt, die Schleife könnte enden, ohne das if überhaupt auszuführen.

In der Praxis ist die sauberste Version dieses Programms ein break mit Wert, wie du es oben gesehen hast: let answer = loop { ... break n * n; ... };. So oder so ist die Lehre dieselbe: Wenn du „für immer, bis ich abbreche“ meinst, schreib loop.

loop ist die richtige Wahl, wenn du vorher nicht weißt, wie oft du etwas wiederholen wirst. Du wartest also darauf, dass eine Bedingung eintritt, statt einen Bereich oder eine Liste durchzuzählen. Zum Zählen oder um eine Collection zu durchlaufen, lesen sich while und for (die als Nächstes kommen) meist besser.

Gib mit loop einen Countdown von 5 bis 1 aus und danach Start!. Tipp: Beginne mit let mut n = 5; und brich mit break ab, sobald n bei 0 ankommt.

Lösung anzeigen
fn main() {
let mut n = 5;
loop {
if n == 0 {
break;
}
println!("{n}...");
n -= 1;
}
println!("Start!");
}

Ausgabe:

5...
4...
3...
2...
1...
Start!
▶ Selbst ausprobieren

Die Prüfung kommt zuerst. Wenn n also 0 ist, stoppt die Schleife, bevor 0... ausgegeben wird.

Beginne bei 1 und verdopple immer weiter. Hol dir mit break und einem Wert die erste Zahl über 1000, und zähle, wie viele Verdopplungen das gebraucht hat. Tipp: Halte einen mut-Zähler außerhalb der Schleife und schreib let power = loop { ... };.

Lösung anzeigen
fn main() {
let mut value = 1;
let mut doublings = 0;
let power = loop {
value *= 2;
doublings += 1;
if value > 1000 {
break value;
}
};
println!("{power} nach {doublings} Verdopplungen");
}

Ausgabe:

1024 nach 10 Verdopplungen
▶ Selbst ausprobieren

break value; beendet die Schleife und übergibt value an power. Der Zähler lebt außerhalb der Schleife und behält deshalb seinen Wert, auch nachdem sie zu Ende ist.

  • loop wiederholt sich endlos, bis ein break die Schleife stoppt – sorg immer dafür, dass es eines gibt.
  • break wert; beendet die Schleife und gibt wert als Ergebnis des ganzen Schleifen-Ausdrucks zurück.
  • Schreib loop, nicht while true: Rust weiß, dass der Rumpf einer loop immer läuft, und kann so deine Variablen besser prüfen.
  • Greif zu loop, wenn du etwas „so lange, bis etwas passiert“ wiederholst – nicht, wenn du eine bekannte Anzahl von Durchläufen zählst.

Kurzer Check

1. Was verhindert, dass eine einfache loop-Schleife endlos läuft?

2. Was bewirkt break count * 2; in einer Schleife?

3. Wann ist loop laut dieser Seite die bessere Wahl als while oder for?

4. Was passiert, wenn du in Rust while true { ... } schreibst?

Punkte: 0 / 4