Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kapitel 03: Fundamente: Variablen & Typen (Sicht für Profis)

Dieses Kapitel behandelt fortgeschrittene Typsystem-Konzepte, das Newtype-Pattern, die Semantik von Konstanten und die Modellierung optionaler Werte.

1. Lernziele

In diesem Abschnitt werden Sie:

  • Das Newtype-Pattern zur Durchsetzung von Typsicherheit auf Domänenebene anwenden.
  • Den Unterschied in der Speicherplatzallokation zwischen const und static analysieren.
  • Shadowing zur Erhöhung der API-Ergonomie und Code-Lesbarkeit nutzen.
  • Strategien zur sicheren Modellierung von numerischen Überläufen im Domänenmodell vergleichen.

2. Item 3: Bevorzuge das Typsystem von Rust gegenüber ad-hoc Annahmen (Newtype-Pattern)

Ein häufiger Fehler in vielen Programmiersprachen ist die Verwendung primitiver Typen für Domänenwerte (z. B. ein f64 für eine Temperatur in Kelvin und ein anderes f64 für Celsius). Dies führt zu logischen Fehlern, die der Compiler nicht erkennen kann.

In Rust nutzen wir das Newtype-Pattern, um Typen auf Domänenebene voneinander abzugrenzen:

// Definition zweier unterschiedlicher Typen ohne Laufzeit-Overhead
struct Celsius(f64);
struct Fahrenheit(f64);

fn main() {
    let temp_c = Celsius(25.0);
    // let temp_f: Fahrenheit = temp_c; // COMPILER-FEHLER: Typkonflikt!
}

Da die Structs als Tupel-Strukturen mit nur einem Feld definiert sind, optimiert der Compiler sie bei der Kompilierung vollständig weg (Zero-Cost Abstraction). Zur Laufzeit existiert nur der primitive f64-Wert.


3. Konstanten (const) vs. Statische Variablen (static)

In Rust müssen Konstanten zur Kompilierzeit auswertbar sein und erfordern zwingend eine explizite Typannotation:

  • const: Besitzt keinen festen Speicherort im RAM. Der Compiler führt bei der Kompilierung ein Inlining durch; der Wert wird direkt als Literal in den Maschinencode kopiert.
  • static: Besitzt eine feste Adresse im Speicher, die über die gesamte Lebensdauer des Programms gültig ist. Statische Variablen erlauben die Deklaration von veränderlichen globalen Zuständen (static mut), deren Zugriff jedoch grundsätzlich als unsafe deklariert werden muss, da Rust keine Garantien für die Threadsicherheit auf dieser Ebene übernehmen kann.

4. Shadowing als ergonomisches API-Design

Professioneller Rust-Code nutzt Shadowing intensiv zur Transformation von Daten. Es verhindert, dass ungültige Zwischenzustände im aktuellen Scope nutzbar bleiben:

#![allow(unused)]
fn main() {
fn verarbeite_eingabe(eingabe_raw: &str) {
    let eingabe = eingabe_raw.trim();
    let eingabe: i32 = eingabe.parse().expect("Ungültiges Format");
    // eingabe ist ab hier sicher als i32 typisiert.
    // Der String-Zustand ist für den Rest der Funktion unzugänglich.
}
}

5. Modellierung von Integer-Überläufen im Domänen-Design

Standardmäßig stürzt Rust im Debug-Modus bei einem Integer-Überlauf (Overflow) mit einer panic ab, während im Release-Modus das mathematische Wrapping (Zweierkomplement-Verhalten) angewendet wird.

Für kritische Berechnungen (z. B. in Finanz- oder Sicherheitsanwendungen) müssen Sie dieses Verhalten explizit steuern:

MethodeVerhaltenAnwendungsfall
wrapping_addSpringt bei Überlauf zurück (z. B. 255 + 1 = 0 bei u8).Hashfunktionen, Kryptografie
saturating_addVerbleibt beim Grenzwert (z. B. 255 + 1 = 255).Audio-Lautstärken, UI-Koordinaten
checked_addLiefert ein Option<T> (None bei Überlauf).Finanzberechnungen, API-Validierung

6. Key Takeaways (Architektur-Richtlinien)

  • Newtypes: Kapseln Sie primitive Datentypen in eigene Structs, um logische Verwechslungen zur Kompilierzeit unmöglich zu machen.
  • Arithmetic Safety: Verlassen Sie sich nicht auf das standardmäßige Überlaufverhalten; nutzen Sie explizite Methoden (checked_add, saturating_add).
  • Ergonomie: Nutzen Sie Shadowing zur Bereinigung von Scopes bei der Typkonversion.