Warum braucht "break" kein Semikolon, wenn eine "Schleife" beendet wird?

Nov 26 2020

Auszug aus Kapitel 3.5 des Rostbuchs:

... wir verwenden das breakSchlüsselwort mit dem Wert counter * 2. Nach der Schleife verwenden wir ein Semikolon, um die Anweisung zu beenden, der der Wert zugewiesen wird result.

Plus das Code-Snippet:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {}", result);
}

Ich verstehe, wie das funktioniert und warum das Ergebnis 20 ist, aber ich habe festgestellt, dass das Programm äquivalent ist, wenn ich das Semikolon in der Zeile entferne, die das Schlüsselwort "break" enthält.

Warum ist das Semikolon in diesem Fall optional?

Antworten

5 E_net4thecurator Nov 26 2020 at 22:30

Ein kürzeres Beispiel:

let _: i32 = loop {
    if true {
        break 3; // ()
    }
};

Dies ist nur ein weiteres Beispiel, bei dem das Semikolon das beabsichtigte Ergebnis nicht beeinträchtigt. Zum einen führt das Einfügen eines Semikolons eine Ausdrucksanweisung ein, die als Einheitentyp ausgewertet wird (). Da die loops und ifAusdrücke weiterhin einen Codeblock zulassen, der denselben Typ auswertet (), stimmen alle Typen überein.

let _: i32 = loop {
    if true {
        break 3 // !
    }
};

Wenn das Semikolon entfernt wird, breakwird das auf den Nie-Typ! ausgewertet, der zu jedem anderen Typ gezwungen wird. Dies bedeutet, dass es jeden Typ erfüllt, der vom äußeren Anwendungsbereich erwartet wird. Es ist also alles in Ordnung, solange Sie nicht versuchen, vor dem Ende des if-Blocks eine andere Anweisung anzuhängen.

Beide breakund returnbewerten !, da ihre Nebenwirkungen implizieren, dass das Programm den natürlichen Workflow nicht durchläuft.

Siehe auch:

  • Warum verwenden Rückgabeausdrücke Semikolons, wenn sie nicht erforderlich sind?
  • Was ist der Unterschied zwischen der Verwendung der return-Anweisung und dem Weglassen des Semikolons in Rust?
  • Wie das Ende einer Funktion statisch bestätigt werden kann, ist nicht erreichbar
3 pretzelhammer Nov 26 2020 at 22:42

Die Rust-Sprachreferenz zu Ausdrucksanweisungen :

Eine Ausdrucksanweisung wertet einen Ausdruck aus und ignoriert sein Ergebnis. In der Regel dient eine Ausdrucksanweisung dazu, die Auswirkungen der Auswertung ihres Ausdrucks auszulösen.

Ein Ausdruck, der nur aus einem Blockausdruck oder einem Kontrollflussausdruck besteht, kann, wenn er in einem Kontext verwendet wird, in dem eine Anweisung zulässig ist, das nachfolgende Semikolon weglassen .

Ich stelle mir vor, dass dies nur der Ästhetik und Ergonomie dient, da fast alles Ausdruck in Rust ist. Wenn das nachfolgende Semikolon nach allen Ausdrücken obligatorisch wäre, müssten wir if-else-Blöcke (die auch Ausdrücke sind) mit Semikolons beenden, was schrecklich aussieht:

if {
    // do something
} else {
    // do something else
}; // <- gross

In ähnlicher Weise können wir das nachfolgende Semikolon bei allen Kontrollflussausdrücken weglassen, da sie einen Kontrollfluss erzeugen. Daher ist die typische Funktion des Semikolons, das Ergebnis des Ausdrucks zu verwerfen und ()stattdessen auszuwerten , irrelevant.

fn five() -> i32 {
    return 5 // to semicolon or not to semicolon? it doesn't matter
}

Im obigen Beispiel macht es keinen Unterschied, ob wir return 5mit einem Semikolon enden oder nicht, da das Ergebnis dieses Ausdrucks ohnehin durch nichts "erfasst" werden kann, da es einen Kontrollfluss erzeugt. Gleiches gilt für andere Kontrollflussausdrücke wie breakund continue.