Marburger | Rust | E-Book | www.sack.de
E-Book

E-Book, Deutsch, 1016 Seiten

Reihe: Rheinwerk Computing

Marburger Rust

Das umfassende Handbuch
1. Auflage 2024
ISBN: 978-3-8362-9020-3
Verlag: Rheinwerk
Format: EPUB
Kopierschutz: 0 - No protection

Das umfassende Handbuch

E-Book, Deutsch, 1016 Seiten

Reihe: Rheinwerk Computing

ISBN: 978-3-8362-9020-3
Verlag: Rheinwerk
Format: EPUB
Kopierschutz: 0 - No protection



Werden Sie Rust-Profi und entwickeln Sie moderne, sichere Software!
Rust ist für sein cleveres Speichermanagement, hervorrangende Sicherheit und viele beliebte Features bekannt. Nutzen Sie das hervorrangende Design dieser Sprache, um moderne und robuste Software auf professionellem Niveau zu entwickeln! Dieses Handbuch begleitet Sie beim Einstieg und stellt Rust dann detailliert vor - sowohl für systemnahe Prorammierung als auch für Enterprise- und Cloud-Anwendungen. Mit vielen gut kommentierten Codebeispielen, Best Practices und einer durchgehenden Demo-Anwendung. Zugleich lassen sich alle Kapitel gut einzeln lesen und zum Nachschlagen verwenden. Der ideale Weg zu fundierten und umfassenden Kenntnissen!

Aus dem Inhalt:

  • Rust installieren, Toolchain aufsetzen
  • Fundierter Einstieg
  • Speichermanagement
  • Traits und Closures
  • Collections und Iteratoren
  • Asynchrone Programmierung
  • Multithreading
  • Arbeiten mit Text
  • Dokumentation und Test automatisieren
  • Schnittstellen zu anderen Sprachen


Marc Marburger hat langjährige Erfahrung in der App- und Softwareentwicklung. Angefangen hat er nach dem Abschluss in Informatik mit C++ und Assembler in der Industrieautomatisierung. Plattformübergreifende Apps beschäftigen ihn seit 2012, von C# auf der Windows-Plattform über Xamarin kommend liegt sein Fokus nun auf Dart und Flutter, die er täglich als freiberuflicher Softwareentwickler in Kundenprojekten einsetzt.
Marburger Rust jetzt bestellen!

Autoren/Hrsg.


Weitere Infos & Material


Materialien zum Buch ... 18  1.  Über dieses Buch ... 19  1.1 ... Was Sie in diesem Buch lernen werden ... 20  1.2 ... Was dieses Buch Ihnen zeigen möchte ... 21  1.3 ... Noch mehr Informationen und Guides ... 22  1.4 ... Danksagung ... 24  2.  Die Installation, die IDE und »Hallo Rust« ... 25  2.1 ... Wie Sie Rust installieren ... 25  2.2 ... Eine Entwicklungsumgebung wählen ... 28  2.3 ... Das erste Programm ... 30  2.4 ... Wie es weitergeht ... 33  3.  Variablen und Datentypen ... 35  3.1 ... Prelude: Die Standardimporte ... 35  3.2 ... Variablen ... 36  3.3 ... Konstanten ... 56  3.4 ... Skalare Datentypen ... 60  3.5 ... Wie Rust mit »Option« auf null verzichtet ... 81  3.6 ... Zusammenfassung ... 84  4.  Speichernutzung und Referenzen ... 87  4.1 ... Wichtige Speicherbereiche ... 87  4.2 ... Eigentumsverhältnisse im Speicher ... 89  4.3 ... Referenzen und der leihweise Zugriff ... 98  4.4 ... Mit Box Objekte im Heap ablegen ... 111  4.5 ... Zusammenfassung ... 121  5.  Strings ... 123  5.1 ... Der String-Slice ... 123  5.2 ... Der String ... 134  5.3 ... Wie Sie Strings formatieren ... 147  5.4 ... Zusammenfassung ... 154  6.  Collections ... 157  6.1 ... Tupel ... 157  6.2 ... Arrays ... 166  6.3 ... Elementbereiche ... 173  6.4 ... Vektoren ... 182  6.5 ... Slices ... 214  6.6 ... HashMap und BTreeMap ... 231  6.7 ... Hashes ... 245  6.8 ... Mengen verwalten ... 248  6.9 ... Die Entry API ... 251  6.10 ... Elemente verschiedener Datentypen in eine Collection einfügen ... 257  6.11 ... Zusammenfassung ... 260  7.  Funktionen ... 263  7.1 ... Der Aufbau einer Funktion ... 264  7.2 ... Funktionszeiger ... 268  7.3 ... Referenzen und Lebenszeiten in Funktionen ... 271  7.4 ... Konstante Funktionen ... 280  7.5 ... Anonyme Funktionen und Closures ... 285  7.6 ... Funktions-Traits ... 302  7.7 ... Zusammenfassung ... 311  8.  Anweisungen, Ausdrücke und Muster ... 313  8.1 ... Von der Anweisung zum Ausdruck und Muster ... 313  8.2 ... Die Zuweisung im Detail ... 316  8.3 ... Speicherausdrücke ... 319  8.4 ... Operatoren ... 325  8.5 ... Konditionale Ausdrücke ... 330  8.6 ... Schleifen ... 342  8.7 ... Muster ... 350  8.8 ... Zusammenfassung ... 364  9.  Fehlerbehandlung ... 367  9.1 ... Fehler, von denen sich das Programm nicht erholen kann ... 367  9.2 ... Erwartbare Fehler behandeln ... 381  9.3 ... Zusammenfassung ... 418

10.  Strukturen ... 421  10.1 ... Daten zusammenhängend ablegen ... 422  10.2 ... Records: Der Struktur-Urtyp ... 423  10.3 ... Strukturen und Instanzen ... 426  10.4 ... Lebenszeiten: Wenn Felder Referenzen enthalten ... 441  10.5 ... Wie Sie dem Compiler mit PhantomData wichtige Typinformationen übergeben ... 449  10.6 ... Eine Datenstruktur ohne feste Größe ... 460  10.7 ... Die drei Strukturen ... 462  10.8 ... Muster ... 466  10.9 ... Daten und Verhalten sind getrennt ... 468  10.10 ... Strukturen in der Praxis: Das Bestellsystem überarbeiten ... 475  10.11 ... Assoziierte Funktionen und die new-Konvention ... 480  10.12 ... Methoden ... 486  10.13 ... Referenzen in assoziierten Funktionen und Methoden ... 501  10.14 ... Praxisbeispiel: Simulationsfähigkeiten im Restaurant-System ... 503  10.15 ... Rekursion in Strukturen ... 507  10.16 ... Typ-Aliasse ... 510  10.17 ... Zusammenfassung ... 512

11.  Traits ... 515  11.1 ... Marker-Traits ... 516  11.2 ... Trait-Implementierungsblöcke ... 517  11.3 ... Sie können ein Trait jeweils für T und &T implementieren ... 541  11.4 ... Super-Traits ... 546  11.5 ... Trait-Objekte ... 549  11.6 ... Beispielprojekt: Trait-Objekte von »Form« ... 564  11.7 ... Undurchsichtige Datentypen zurückgeben ... 574  11.8 ... Traits in der Praxis ... 578  11.9 ... Zusammenfassung ... 627

12.  Enumerationen ... 631  12.1 ... Die Eigenschaften einer Enumeration ... 632  12.2 ... Verschiedene Variant-Typen ... 644  12.3 ... Enumerationen und Muster ... 656  12.4 ... Implementierungsblöcke und Verhalten ... 660  12.5 ... Zusammenfassung ... 667

13.  Module, Pfade und Crates ... 669  13.1 ... Das Modul ... 669  13.2 ... Pfade ... 697  13.3 ... Vom Crate zum Paket, vom Paket zum Workspace ... 721  13.4 ... Zusammenfassung ... 777

14.  Generische Programmierung ... 781  14.1 ... Von der Vorlage zur Konkretisierung: Monomorphisierung ... 781  14.2 ... Typparameter, generische Konstanten und Lebenszeiten ... 783  14.3 ... Syntaktische Elemente, die generisch sein können ... 785  14.4 ... Mehr zu Trait-Grenzen ... 789  14.5 ... Zusammenfassung ... 794

15.  Iteratoren ... 797  15.1 ... Wie Sie einen Iterator beziehen ... 798  15.2 ... Iterator-Adapter ... 805  15.3 ... Einen Iterator konsumieren ... 816  15.4 ... Zusammenfassung ... 822

16.  Nebenläufige und asynchrone Programmierung ... 823  16.1 ... Nebenläufige Programmierung ... 824  16.2 ... Smart Pointer ... 876  16.3 ... Asynchrone Programmierung ... 893  16.4 ... Zusammenfassung ... 915

17.  Makros ... 917  17.1 ... Deklarative Makros ... 917  17.2 ... Prozedurale Makros ... 939  17.3 ... Zusammenfassung ... 950

18.  Automatische Tests und Dokumentation ... 953  18.1 ... Tests ... 954  18.2 ... Rust-Projekte dokumentieren ... 966  18.3 ... Zusammenfassung ... 979

19.  Unsafe Rust und das Foreign Function Interface ... 981  19.1 ... Unsafe Rust ... 981  19.2 ... Primitive Zeiger ... 987  19.3 ... Union ... 998  19.4 ... Foreign Function Interface ... 1001  19.5 ... Zusammenfassung ... 1005  Index ... 1007


3.2    Variablen


Bits und Bytes benötigen ein Zuhause. Damit die Zahlen, logischen Aussagen und Zeichenketten nicht haltlos in der Codesuppe umhertreiben, führen wir beim Programmieren Variablen ein. Das geschieht in zwei Schritten: bei der Deklaration des Bezeichners und dessen Typs sowie bei der Zuweisung eines Werts, der Initialisierung.

Die nächsten Abschnitte führen Sie durch die Eigenschaften von Variablen, insbesondere betrachten wie die Veränderlichkeit. Daneben behandeln wir Sprachfeatures wie die Typinferenz und das Shadowing. Die Frage nach der Veränderlichkeit von Variablen und Referenzen stellt einen zentralen Baustein von Rust dar: Grundsätzlich sind alle Variablen und Referenzen unveränderlich, nachdem Sie sie eingeführt haben. Erst das Schlüsselwort mut, kurz für mutable (zu Deutsch »veränderlich«), das Sie in der Deklaration einsetzen, ermöglicht eine erneute Zuweisung oder den schreibenden Zugriff.

Diese Eigenschaften führt ein Beispiel am Ende des Abschnitts vor. Dort werden Sie sehen, wie Sie in Rust eine Zeichenkette einlesen und in eine numerische Repräsentation bringen.

3.2.1    Die Deklaration einer Variable


Rust ist eine statisch typisierte Sprache. Jeder Wert, jede Variable, jede Funktion oder jede Struktur weist folglich einen festen Typ auf. Eine Variable kann nur jene Werte binden, die dem eigenen Datentyp entsprechen: Einer Variable vom Typ einer Ganzzahl, wie in Listing 3.1, können Sie zum Beispiel keine Zeichenkette und nicht einmal eine Fließkommazahl zuweisen!

Das statische Typsystem von Rust unterstützt das Verständnis von Rust-Code. Es fällt leichter, der Verwendung einer Variable im Code zu folgen, wenn der Typ verbindlich ist. Der Compiler erhält überdies Zusagen über deren Speicherbedarf und kann etwaige Optimierungen vornehmen. Sie können zwar den Typ und den Wert in einem Zug angeben (mehr dazu folgt in Abschnitt 3.2.2), aber oft steht der initiale Wert nicht fest, sodass Sie eine Variable zunächst deklarieren. Das erspart Ihnen, die Variable unnötigerweise für kurze Zeit zuzuweisen.

Angenommen, Sie möchten das Alter einer Person in Ihrem Programm einlesen. Damit Sie die Eingabe abspeichern können, führen Sie mit dem Schlüsselwort let die Variable alter ein. Etwa so:

fn main() {
let alter: i8;
}

Listing 3.1     Die Deklaration der Variable »alter«

Im Rumpf der Funktion main sehen Sie die Deklaration einer Variable. Das Schlüsselwort let eröffnet die Zeile und führt den Bezeichner (engl. Identifier) alter für die Variable ein. Darauf folgt der Doppelpunkt, mit dem Sie den Datentyp angeben. Diese Schreibweise unterscheidet sich deutlich von C und C++. Rust ist damit jedoch nicht allein, denn unter anderem setzen auch die Programmiersprachen Swift und Kotlin diese Syntax ein.

Der Typ i8 repräsentiert einen Integer von 8 Bit Breite. Integer ist das englische Wort für Ganzzahl. Neben i8 kennt Rust weitere numerische Werte, etwa den Datentyp i16 für eine Ganzzahl mit 16 Bit Breite. Die Typen stehen Ihnen in gängigen Bitgrößen (16, 32, 64 …) zur Auswahl. In Abschnitt 3.4.2, »Integer«, stelle ich Ihnen die anderen Ganzzahl-Datentypen vor.

Warum eigentlich »let«?

Ist Ihnen das Schlüsselwort let bereits in anderen Programmiersprachen begegnet? Woher kommt let? Tatsächlich fand sich dieses Schlüsselwort schon in BASIC! Im Jahr 1964 erschien dessen erstes Benutzerhandbuch und erklärte die Verwendung von let.

Der Ausdruck lässt sich ursprünglich auf die Mathematik zurückführen. Erinnern Sie sich an Aufgabenstellungen wie »Gegeben sei X=2 …«? Auf Englisch sagt man dann: »Let X=2«. Somit lehnte sich BASIC an die mathematische Ausdrucksweise an. Damals waren die Felder Mathematik und »Informatik« noch viel enger miteinander verbunden. Tatsächlich wurde eine Vorstellung von Software-Engineering als etwas Eigenständiges (abseits der Hardware) erst auf der NATO Conference 1968 in Garmisch herausgearbeitet!

Auch heute verwenden neben Rust einige Sprachen das Schlüsselwort let. So findet sich let außer in Rust ebenfalls in JavaScript (seit ES2015), Swift und C# (LINQ).

3.2.2    Eine Variable initialisieren


Die Variable alter mit dem Typ i8 wartet nun auf eine Wertzuweisung. Die Initialisierung als zweiter Schritt steht noch aus. Falls Sie eine Variable auslesen möchten, die Sie davor nicht initialisiert haben, meldet der Compiler sofort einen Fehler!

Hierdurch verhindert Rust ein undefiniertes Verhalten: Ohne den Fehler könnte das Speicherobjekt der Variable ein Bitmuster aufweisen, das mit dem Datentyp inkompatibel ist. Ein Beispiel: Der Datentyp String stellt durch seine Schnittstellen sicher, dass sich darin ausschließlich Zeichen befinden, die als UTF-8 kodiert worden sind. Würden Sie einen String deklarieren und vor der Initialisierung auslesen, würden sich im Speicherobjekt Bitmuster befinden, die UTF-8 nur zufällig oder gar nicht repräsentieren kann.

Folgendermaßen weisen Sie der Variable im Zuge der Deklaration einen Wert zu:

fn main() {
let alter: i8 = 42;
}

Listing 3.2     Die Variable »alter« initialisieren

Rust prüft an dieser Stelle zwei Dinge:

  • Weist der Wert, den Sie zuweisen wollen, den gleichen Datentyp auf oder müssten Sie ihn zuvor konvertieren?

  • Und wird der Wert in den Wertebereich des Zieltyps passen?

Im Beispiel entspricht das Literal 42 den Anforderungen, die ein vorzeichenbehafteter und acht Bit breiter i8 aufstellt, dessen positiver Maximalwert die Zahl 127 nicht übersteigen kann (Zweierkomplement, -128 bis 127).

Fehler wie Überläufe führen zu Sicherheits- und Speicherfehlern oder zumindest zu Verwirrung über das Ergebnis. Die Prüfung des Wertebereichs zur Kompilierzeit stellt vor diesem Hintergrund eine bedeutende Hilfe für den Programmierer dar. Während etwa C oder C++ höchstens eine Warnung über die implizite Umwandlung einer größeren Ganzzahl in eine kleinere ausgibt, meldet der Rust-Compiler einen Fehler! C oder C++-Linter können Sie freilich so konfigurieren, dass eine Warnung zu einem Fehler führt. Diese Maßnahme und die vorauseilenden Diskussionen im Team über das Für und Wider sparen Sie sich jedoch in Rust.

Eine Probe gefällig? Ändern Sie den Wert 42 zu 420, und reichen Sie das Programm an den Compiler weiter. Das Ergebnis:

error: literal out of range for `i8`
–> src/main.rs:6:19
|
6 | let alter: i8 = 420;
| ^^^
|
= note: `#[deny(overflowing_literals)]` on by default
= note: the literal `420` does not fit into the type `i8` whose range is
`-128..=127`
= help: consider using the type `i16` instead

Der Compiler markiert die Fehlerposition innerhalb des Codeschnipsels. Darunter befinden sich Informationen zu der Regel, die vom Code verletzt wurde, und Hinweise dazu, wie Sie das Problem beheben. Rust lässt Sie mit einem Fehler also nicht allein. Tatsächlich unternimmt das Sprach-Team von Rust große Anstrengungen, um die bestmöglichen Fehlermeldungen auszugeben.

3.2.3    Eine Variable mit dem Schlüsselwort »mut« veränderlich machen


Viele Programmiersprachen erlauben es Ihnen, eine Variable ohne Weiteres nach der Initialisierung zu ändern. In Rust müssen Sie dagegen bereits bei der Deklaration das Schlüsselwort mut einsetzen. Erst dann dürfen Sie eine Variable überschreiben. Rust-Variablen sind nach der Deklaration standardmäßig als unveränderlich eingefroren (engl. frozen), während Sie diesen Effekt etwa in C++ mit dem Schlüsselwort const erst aktiv herbeiführen müssen.

Sollten Sie die Unveränderlichkeit verletzen, weist der Compiler Sie umgehend darauf hin. Ein Beispiel:

fn main() {
let alter: i8 = 42;

// Fehler
alter = 21;
}

Listing 3.3     Die Variable ist vor der erneuten Zuweisung geschützt.

Der Compiler meldet, dass alter schon bei der Einführung einen Wert erhalten hat. Nachträglich dürfen Sie die Variable demnach nicht verändern:

error[E0384]: cannot assign twice to immutable variable `alter`
--> src/main.rs
|
2 | let alter: i8 = 42;
| -----
| |
| first assignment to `alter`
| help: consider making this binding mutable: `mut alter`
4 |...


Marburger, Marc
Marc Marburger hat langjährige Erfahrung in der App- und Softwareentwicklung. Angefangen hat er nach dem Abschluss in Informatik mit C++ und Assembler in der Industrieautomatisierung. Plattformübergreifende Apps beschäftigen ihn seit 2012, von C# auf der Windows-Plattform über Xamarin kommend liegt sein Fokus nun auf Dart und Flutter, die er täglich als freiberuflicher Softwareentwickler in Kundenprojekten einsetzt.



Ihre Fragen, Wünsche oder Anmerkungen
Vorname*
Nachname*
Ihre E-Mail-Adresse*
Kundennr.
Ihre Nachricht*
Lediglich mit * gekennzeichnete Felder sind Pflichtfelder.
Wenn Sie die im Kontaktformular eingegebenen Daten durch Klick auf den nachfolgenden Button übersenden, erklären Sie sich damit einverstanden, dass wir Ihr Angaben für die Beantwortung Ihrer Anfrage verwenden. Selbstverständlich werden Ihre Daten vertraulich behandelt und nicht an Dritte weitergegeben. Sie können der Verwendung Ihrer Daten jederzeit widersprechen. Das Datenhandling bei Sack Fachmedien erklären wir Ihnen in unserer Datenschutzerklärung.