Rust-Werkstatt

Gratis Leseprobe

So fühlt sich die Werkbank an.

Die Einleitung „Bevor wir anfangen“ und das komplette Kapitel 2 „Hallo, Rust!“ aus dem Buch. Dein erstes Rust-Programm, inklusive absichtlichem Fehler.

Einleitung · Teil 1: Grundlagen

Bevor wir anfangen

Stell dir vor, wir sitzen nebeneinander an einer Werkbank. Du hast die Tastatur vor dir, ich sitze daneben. Ich sage Dinge wie: „Probier mal …“, „Warte, schau dir die Meldung genau an …“ und „Jetzt bauen wir das aus.“

So ist dieses Buch gedacht. Du bekommst keine fertigen Programme zum Abtippen. Wir fangen jedes Mal mit fast nichts an, lassen es laufen, verändern etwas und schauen, was passiert. Das Programm wächst Schritt für Schritt, und du siehst bei jedem Schritt, warum es so wird, wie es wird.

Für wen ist dieses Buch?

Für dich, wenn du noch nie programmiert hast. Oder wenn du es schon einmal versucht hast und irgendwo hängen geblieben bist. Du brauchst keine Vorkenntnisse. Wenn du weißt, wie man eine Datei speichert und ein Programm startet, kannst du loslegen. Alles andere erkläre ich dir, und zwar langsam. Wenn dir etwas zu ausführlich vorkommt, überspring es einfach. Zu knapp ist für Einsteiger schlimmer als zu ausführlich.

Wenn du schon in einer anderen Sprache programmiert hast, wirst du manches schneller durchblättern. Lass dich nicht täuschen: Rust funktioniert in einigen Dingen grundlegend anders als die meisten Sprachen. Kapitel, die du zu kennen glaubst, verraten oft einen Unterschied im Detail.

Warum Rust?

Programmiersprachen sind Werkzeuge, und jedes Werkzeug hat Stärken. Rust wurde gebaut, damit man schnelle Programme schreiben kann, ohne bei der Sicherheit zu schummeln. Viele schnelle Sprachen lassen dich Fehler machen, die erst beim Ausführen auffallen: Abstürze, kaputte Daten, Sicherheitslücken. Rust verlangt dafür, dass du dem Compiler, dem Übersetzer deines Programms, genau erklärst, was du vorhast. Dafür findet er viele Fehler, bevor das Programm überhaupt läuft.

Das hat einen Preis, und ich verspreche dir, ehrlich darüber zu sprechen: Rust ist am Anfang strenger und anstrengender als andere Sprachen. Du wirst dich manchmal über den Compiler ärgern. Er will meistens etwas Vernünftiges, und seine Meldungen sind für Menschen geschrieben. Dieses Buch bringt dir bei, sie zu lesen.

Was bauen wir?

Wir lernen die Sprache von Grund auf und bauen währenddessen zwei Dinge: kleine Programme mit Fenstern (mit der Bibliothek iced, sprich „eisd“) und das Rezeptbuch, ein Kochbuch mit Vorratsschrank, und ein kleines Spiel, Küchenstress. Beides hält die Theorie in der Praxis fest. Am Ende hast du ein Programm, das du wirklich benutzen kannst, und du verstehst die Sprache so, dass du alleine weiterkommst.

Wie arbeiten wir?

Jedes Kapitel ist in kleine Schritte unterteilt. Damit du dich zurechtfindest, gibt es immer wiederkehrende Abschnitte:

Eine Bitte noch: Tippe den Code selbst ab, auch wenn es nur drei Zeilen sind. Deine Finger lernen mit, und du machst Tippfehler. An denen lernst du, wie der Compiler mit dir spricht. Kopieren ist erlaubt, aber es ist wie Schwimmen lernen, indem man anderen zuschaut.

Alle Beispiele wurden mit Rust 1.99 und iced 0.14 geprüft, und jede Fehlermeldung in diesem Buch stammt vom echten Compiler. Neuere Versionen funktionieren meist genauso, aber Meldungen können sich im Wortlaut etwas ändern.

Ein Wort zu den Fehlern

Du wirst Fehler machen. Wirklich. Jeder Programmierer macht jeden Tag welche, auch nach 20 Jahren. Der Unterschied zwischen Anfängern und Profis ist nicht, dass Profis weniger Fehler machen, sondern dass sie keine Angst vor ihnen haben. Rust hat dafür einen riesigen Vorteil: Seine Fehlermeldungen sind für Menschen geschrieben und schlagen oft schon die Lösung vor. Lies sie, statt wegzuklicken.


Kapitel 2

Hallo, Rust!

Jetzt wird es ernst, aber nicht schwer. Wir lassen den Computer zum ersten Mal etwas für uns tun.

Ein Projekt anlegen

Ein Programm besteht selten nur aus einer Datei. Rust-Programme leben in einem Projekt, das ist ein Ordner mit ein paar Dateien, die zusammengehören. Cargo legt ihn für uns an.

An der Werkbank

Wechsle im Terminal in deinen Arbeitsordner werkstatt und lege das Projekt an:

$ cargo new hallo_rust
$ cd hallo_rust

Cargo antwortet:

    Creating binary (application) `hallo_rust` package

„Binary“ heißt hier: ein Projekt, das ein startbares Programm ergibt, im Gegensatz zu einer Bibliothek. Die erste Zeile erzeugt einen neuen Ordner hallo_rust samt Inhalt. Die zweite wechselt hinein.

Was hat Cargo uns hingestellt?

Öffne den Ordner hallo_rust in VS Code (im Menü: Datei, Ordner öffnen). Du siehst:

Cargo.toml
[package]
name = "hallo_rust"
version = "0.1.0"
edition = "2024"

[dependencies]

Später kommen zwei weitere Dinge dazu, wenn du das Projekt baust: ein Ordner target, in den Cargo alle Zwischen- und Endergebnisse legt, und eine Datei Cargo.lock, die genau festhält, welche Versionen von Bibliotheken benutzt wurden. Beide musst du nicht anfassen.

Öffne src/main.rs. Cargo hat sie schon befüllt:

src/main.rs
fn main() {
    println!("Hello, world!");
}

Drei Zeilen. Du hast noch nichts geschrieben und besitzt bereits ein lauffähiges Programm.

Starten

$ cargo run

Cargo ruft den Compiler auf, übersetzt dein Programm und startet es. Du siehst etwa:

   Compiling hallo_rust v0.1.0 (...)
    Finished `dev` profile [unoptimized + debuginfo]
              target(s) in 0.17s
     Running `target/debug/hallo_rust`
Hello, world!

Die letzte Zeile ist die Ausgabe deines Programms. Die anderen Zeilen sind Cargos Berichte, was es gerade tut. Lies sie einmal ganz:

Starte das Programm noch einmal mit cargo run. Diesmal fehlt die Zeile mit „Compiling“: Cargo hat gemerkt, dass sich nichts geändert hat, und hat nichts neu übersetzt.

Drei Befehle, ein Unterschied

Gelegentlich möchtest du ganz von vorn anfangen: cargo clean löscht den Ordner target. Der nächste Lauf übersetzt alles neu.

Jetzt du: Ändere den Text

Ändere den Text in "Hallo, Werkstatt!", speichere die Datei (Cmd + S oder Strg + S) und starte noch einmal mit cargo run. Siehst du, dass Cargo dein Programm automatisch neu übersetzt hat?

Hinschauen: Was steht da eigentlich?

Gehen wir die drei Zeilen durch, Stück für Stück:

Zeile 1
fn main() {

fn ist die Abkürzung für „function“, auf Deutsch Funktion. Eine Funktion ist ein benannter Block von Anweisungen, ein kleines Teilprogramm. Diese hier heißt main („Haupt“). Jedes Rust-Programm beginnt in main. Wenn du dein Programm startest, sucht der Computer diese Funktion und führt sie aus.

Die runden Klammern () nach dem Namen sind für Dinge, die man der Funktion mitgeben kann. Bei main brauchen wir nichts, also stehen sie leer da. Die geschweifte Klammer { öffnet den Block, also den Inhalt der Funktion.

Zeile 2
    println!("Hallo, Werkstatt!");

println kommt von „print line“, also „drucke eine Zeile“. Es gibt den Text in Anführungszeichen im Terminal aus und macht dann einen Zeilenumbruch.

Das Ausrufezeichen nach println verrät etwas Besonderes: Das ist ein Makro, keine normale Funktion. Für den Anfang reicht dir: Ein Makro ist ein Werkzeug, das mehr kann als eine Funktion. Zum Beispiel versteht println! Platzhalter in den Anführungszeichen, wie du gleich sehen wirst.

Am Ende der Zeile steht ein Semikolon ;. Es beendet eine Anweisung, so wie ein Punkt einen Satz beendet. Das Semikolon ist in Rust sehr wichtig. In Kapitel 6 lernst du, wann man es auch weglassen kann.

Zeile 3
}

Die schließende geschweifte Klammer beendet die Funktion.

Stolperstelle

Fehler sind das beste Lernmaterial. Wir machen absichtlich einen. Schreibe eine zweite Zeile dazu und lösche das Semikolon hinter der ersten:

src/main.rs
fn main() {
    println!("Hallo, Werkstatt!")
    println!("Zweite Zeile");
}

Starte mit cargo run. Der Compiler schimpft, und zwar so:

error: expected `;`, found `println`
 --> src/main.rs:2:34
  |
2 |     println!("Hallo, Werkstatt!")
  |                                   ^ help: add `;` here
3 |     println!("Zweite Zeile");
  |     ------- unexpected token

Übersetzt: „Ich habe ein Semikolon erwartet, aber das nächste println gefunden.“ Der Compiler zeigt dir die Zeile, den genauen Ort (Zeile 2, Zeichen 34) und sagt dir sogar, was du tun sollst: add ; here. Setze das Semikolon wieder ein, und alles läuft.

(Hinter der letzten Anweisung einer Funktion darf es übrigens fehlen. Warum, erfährst du in Kapitel 6.)

Mehr aus println! herausholen

println! kann mehr als feste Texte ausgeben. Probiere dieses Programm:

src/main.rs
fn main() {
    let name = "Rustifer";
    let alter = 3;
    println!("Hallo, {}!", name);
    println!("Hallo, {name}!");
    println!("{0} ist {1} Jahre alt, {1} Jahre!", name, alter);
    println!("{name:?} und {alter:?}");
    println!("Klammern: {{ und }}");
    print!("ohne Umbruch, ");
    print!("dann weiter\n");
    eprintln!("das geht auf den Fehlerkanal");
}

Die Ausgabe:

Hallo, Rustifer!
Hallo, Rustifer!
Rustifer ist 3 Jahre alt, 3 Jahre!
"Rustifer" und 3
Klammern: { und }
ohne Umbruch, dann weiter
das geht auf den Fehlerkanal

Zeile für Zeile:

Kommentare

Manchmal willst du etwas in den Code schreiben, das nur für Menschen gedacht ist. Dafür sind Kommentare da. Der Compiler überliest sie:

src/main.rs
fn main() {
    // Ein Kommentar für Menschen
    println!("Hallo"); // auch hinter einer Zeile
    /* Ein langer
       Kommentar */
    println!("Welt");
}

Ein guter Kommentar sagt, warum etwas so ist, nicht was da steht. Was dasteht, sieht man ja.

Jetzt du: Eine Visitenkarte

Schreibe ein Programm, das eine Visitenkarte ausgibt: einen Rahmen aus Strichen, darin Name, Beruf und Ort in je einer Zeile. Verwende dazu mindestens zwei Variablen mit {name} im Text.

Erst selbst probieren, dann hier die Lösung ansehen
Lösung (Anhang A)
fn main() {
    let name = "Volker Daehn";
    let beruf = "Tischler";
    let ort = "Hamburg";
    println!("+------------------------+");
    println!("| {name}");
    println!("| {beruf}");
    println!("| {ort}");
    println!("+------------------------+");
}

Ins Werkzeugfach

  • Jedes Rust-Programm startet in der Funktion fn main().
  • Ein Projekt besteht aus Cargo.toml (Steckbrief) und src/main.rs (Quelltext). Der Ordner target ist Cargos Werkstatt.
  • cargo run übersetzt und startet. cargo check prüft nur und ist am schnellsten.
  • Mit println!("Text {name}") gibst du eine Zeile aus. print! ohne Umbruch, eprintln! auf den Fehlerkanal.
  • {x:?} gibt den Wert in der Debug-Form aus.
  • Anweisungen enden meist mit einem Semikolon.
  • Kommentare: // bis Zeilenende, /* */ für mehrere Zeilen.

Weiter im Buch

Kapitel 3: Variablen – Was darf sich ändern?

Dein Programm lernt, sich Dinge zu merken. Dazu 116 weitere Kapitel, bis aus den ersten drei Zeilen ein fertiges Programm für drei Systeme geworden ist.