From 998c1962b606ca58dad6eaed457a8f89df6b250b Mon Sep 17 00:00:00 2001 From: Daniel Kluge Date: Mon, 22 Aug 2022 17:04:01 +0200 Subject: [PATCH] Add new rust chapter --- diaries/rust/09 - Errors und panic.adoc | 104 ++++++++++++++++++++++++ list.json | 3 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 diaries/rust/09 - Errors und panic.adoc diff --git a/diaries/rust/09 - Errors und panic.adoc b/diaries/rust/09 - Errors und panic.adoc new file mode 100644 index 0000000..7698c66 --- /dev/null +++ b/diaries/rust/09 - Errors und panic.adoc @@ -0,0 +1,104 @@ +:experimental: +:docdatetime: 2022-08-22T17:04:01+02:00 + += Errors und `panic!` + +https://doc.rust-lang.org/book/ch09-00-error-handling.html[Link zum Buch] + +== `panic!` + +Dieses Makro it furchtbar simpel: Es macht Panik und das Programm stirbt mit einem Fehler. +Diesen Fehler kann man auch nicht catchen. + +Wenn `RUST_BACKTRACE` als Umgebungsvariable gesetzt ist, wird auch noch ein langer Traceback angezeigt, allerdings nur, solange Debug-Symbole aktiviert sind (also bei `cargo run` oder `cargo build` ohne `--release`). + +Will man gar kein Traceback und kein "unwinding" (das "hochgehen" durch den Funktionsstack und Aufräumen), kann man auch noch folgendes zu seiner `Cargo.toml` hinzufügen: + +[source, toml] +---- +[profile.release] +panic = 'abort' +---- + +== `Result` + +Der Result-Datentyp ist deutlich besser für mögliche Fehler geeignet, die das Programm abfangen und bearbeiten kann. +Falls zum Beispiel eine Datei auf dem Dateisystem nicht existiert, ist es ja manchmal gewünscht, dass diese Datei dann einfach angelegt wird. + +Der `Result`-Typ ist ein Enum von `Ok` und `Error`. +Also kann dann mit `match` geprüft werden, was genau wir gerade bekommen haben. +Alternativ können auch Funktionen wie `unwrap_or_else(|error| {...})` genutzt werden. + +`Ok` verhält sich wie `Some` und sollte zurückgegeben werden, wenn alles glatt läuft. + +`Error` beinhaltet einen Fehler. +Der genaue Fehler kann mit `error.kind()` erfahren werden; ein weiteres `match` ist dann eine "genauere" Fehlerbehandlung. + +Ein volles Beispiel mit ganz viel `match`: + +[source, rust] +---- +use std::fs::File; +use std::io::ErrorKind; + +fn main() { + let greeting_file_result = File::open("hello.txt"); + + let greeting_file = match greeting_file_result { + Ok(file) => file, + Err(error) => match error.kind() { + ErrorKind::NotFound => match File::create("hello.txt") { + Ok(fc) => fc, + Err(e) => panic!("Problem creating the file: {:?}", e), + }, + other_error => { + panic!("Problem opening the file: {:?}", other_error); + } + }, + }; +} +---- + +=== `unwrap()` und `expect()` + +Machen aus einem `Result` entweder ein `T` oder eine `panic!`. +Bei `expect()` kann man noch die Fehlermeldung festlegen. + +Warum man jemals `unwrap()` nehmen sollte, erschließt sich mir nicht ganz. + +=== `?` + +Oft schreibt man Funktionen so, dass Fehler weiter "hochgegeben" werden, falls man welche bekommt. +`?` macht genau das bei einem Result. +Codemäßig erklärt: + +[source, rust] +---- +let a = match result { + Ok(nummer) => nummer, + Err(e) => return Err(e), +}; + +// Ergibt das selbe wie + +let a = result?; +---- + +Das `?` kann auch für zum Beispiel `Option` verwendet werden, dann returned es natürlich `None`. + +=== Rückgaben von `main()` + +Bis jetzt hat `main()` immer nichts, also implizit `()` zurückgegeben. +Manchmal wollen wir ja aber auch was anderes als "0" als return code haben. +Wir können Tatsächlich auch ein Result zurückgeben. Und zwar ein `Result<(), Box>`. +Der zweite Typ dort, kann wohl als "irgendein Fehler" gelesen werden und wird später noch erklärt. + +Allgemein kann aber jedes Objekt, dass `std::process::Termination`-Trait implementiert von main als Rückgabe genutzt werden. + +== Wann `Result`, wann `panic!`? + +Der Artikel ist sehr sehr sehr lang, aber eigentlich sagt er: +"Panic nur wenn es eben nicht gerettet werden kann." +Und obviously in Tests. + +Und man kann natürlich auch tolle eigene Fehlertypen für Result bauen. diff --git a/list.json b/list.json index cb055a7..f87d00c 100644 --- a/list.json +++ b/list.json @@ -44,7 +44,8 @@ { "title": "Structs", "filename": "05 - Structs"}, { "title": "Enums", "filename": "06 - Enums"}, { "title": "Crates & Modules", "filename": "07 - Management"}, - { "title": "Collections", "filename": "08 - Collections"} + { "title": "Collections", "filename": "08 - Collections"}, + { "title": "Errors und panic!", "filename": "09 - Errors und panic"} ] }, {