Einstiegshürde realistisch einschätzen

Ist Rust schwer? Was in den ersten Wochen passiert

Die Syntax kostet dich Tage, das Eigentumsmodell kostet Wochen, und die Übersetzungszeiten kosten dich den gewohnten Rhythmus. Alle drei lassen sich einplanen, wenn man sie kennt.

KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Seit 1997 am Markt Kleine Gruppen Präsenz und Live-Online Zertifizierte Trainer
Worum es geht

Der Aufwand liegt nicht dort, wo ihn die meisten einplanen

Der übliche Plan lautet: zwei Tage Kurs, danach ins Projekt. Für die Syntax geht das auf. Es scheitert an der ersten Datenstruktur, die keine schlichte Liste ist, also an einem Zwischenspeicher, in den mehrere Stellen schreiben, an einem Baum, dessen Knoten auf ihren Elternknoten zeigen, oder an einem Konfigurationsobjekt, das überall herumgereicht wird. In jeder anderen Sprache sind das Aufgaben von zwanzig Minuten. In Rust ist es der Punkt, an dem du lernst, dass sich der Entwurf ändern muss und nicht der Code.

Die Frustrationskurve verläuft dabei nicht gerade. Die erste Woche fühlt sich gut an, die zweite fühlt sich an, als arbeite die Sprache gegen dich, und die Phase, in der du denselben Fehler zum fünften Mal nachschlägst, entscheidet darüber, ob jemand dranbleibt oder anfängt, überall clone hinzuschreiben, damit Ruhe ist. Klonen ist an vielen Stellen legitim, als Reflex erzeugt es aber Code, der langsam ist und gleichzeitig verschweigt, wie die Daten eigentlich zusammenhängen.

Teuer wird das, wenn ein Team das erste Rust-Projekt schätzt wie ein Go- oder Java-Projekt. Nach drei Wochen hält die Schätzung für die Teile, die einem Lehrbuchbeispiel ähneln, und bricht bei den Teilen, die das nicht tun. Danach hat Rust im Haus einen Ruf, und dieser Ruf ist deutlich schwerer zu reparieren als der Code.

KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Symptom, Ursache, Lösung

Die fünf Sackgassen, in denen der Einstieg üblicherweise stecken bleibt

Was hier steht, sind keine Anfängerfehler im Sinne von Unwissen, sondern die Stellen, an denen Gewohnheiten aus anderen Sprachen zuverlässig gegen das Eigentumsmodell laufen. Wer sie vorher kennt, verliert dort Stunden statt Tage.

Symptom

Nach zwei Wochen kompiliert alles, aber der Code steckt voller clone und to_string, und die Rust-Fassung ist langsamer als die Python-Fassung davor.

Ursache

Klonen ist der schnellste Weg, den Compiler ruhigzustellen, und deshalb der erste Reflex. Es beseitigt das Symptom und verschiebt die Frage, wem die Daten gehören, statt sie zu beantworten.

Lösung

Geh die Klone einzeln durch und frag pro Stelle: Braucht diese Funktion die Daten wirklich, oder reicht ihr ein Blick darauf? Meistens genügt eine Referenz als Parameter, oft reicht &str statt String und ein Ausschnitt statt eines eigenen Vec. Klone beim Laden von Konfiguration und beim Aufbau lässt du stehen, die kosten nichts.

Symptom

Jede Änderung braucht Minuten bis zur Rückmeldung, und der gewohnte Rhythmus aus Ändern und Ausprobieren ist weg.

Ursache

Rust übersetzt Generics für jeden verwendeten Typ neu und optimiert aggressiv. Dazu kommt der Bindeschritt am Ende, der bei einem großen Programm einen erheblichen Teil der Zeit ausmacht.

Lösung

Beim Schreiben cargo check statt cargo build nutzen, das prüft Typen und Ausleihen ohne fertiges Programm. Das Projekt in einen Workspace aus mehreren Crates aufteilen, damit eine Änderung nicht alles neu übersetzt. Für den Bindeschritt einen schnelleren Linker eintragen. Und Tests so schneiden, dass nicht jeder Durchlauf das ganze Programm braucht.

Symptom

Ein Modell, das in Java in zwanzig Minuten stand, lässt sich nicht übertragen: Knoten mit Verweis auf den Elternknoten, ein Zwischenspeicher, in den mehrere Teile schreiben, ein Objekt, das überall herumgereicht wird.

Ursache

Das sind Geflechte aus Zeigern, die in einer Sprache mit Speicherbereinigung nichts kosten. Rust verlangt an jeder Kante eine Aussage darüber, wer den Wert besitzt und wie lange er lebt, und ein Geflecht hat darauf keine eindeutige Antwort.

Lösung

Zeiger durch Indizes ersetzen: Alle Knoten liegen in einem Vec, Kanten sind Zahlen statt Referenzen. Für geteilten Besitz innerhalb eines Threads Rc, mit veränderlichem Inhalt Rc mit RefCell, über Threads hinweg Arc mit Mutex. Wichtig ist die Reihenfolge: erst das Modell umbauen, erst danach zu diesen Typen greifen.

Symptom

Der Compiler meldet, ein Wert sei verschoben worden, obwohl im Quelltext nirgends etwas von Verschieben steht.

Ursache

Beim Zuweisen oder Übergeben eines Werts, der keine Kopie erlaubt, geht der Besitz an die neue Stelle über, und die alte Variable ist danach nicht mehr benutzbar. Bei Zahlen und anderen kleinen Typen passiert das nicht, deshalb fällt es erst bei String, Vec oder eigenen Strukturen auf. Ein häufiger Auslöser ist eine for-Schleife, die direkt über die Sammlung läuft statt über &sammlung, denn die verbraucht die Sammlung.

Lösung

Entscheide pro Aufruf, ob die Funktion den Wert wirklich übernehmen soll. Wenn nicht, nimm eine Referenz als Parameter und ändere die Signatur entsprechend. Wenn doch und du brauchst den Wert danach noch, ist an dieser Stelle ein Klon die richtige Antwort und keine Notlösung.

Symptom

Der Kurs war gut, aber drei Wochen später sitzt nichts mehr davon, weil im Projekt weiter C# oder Java ansteht.

Ursache

Rust behält man nicht nebenher. Ohne eine Aufgabe, an der die Regeln regelmäßig weh tun, verblasst genau der Teil, der neu war, und übrig bleibt die Syntax, die ohnehin niemandem Probleme macht.

Lösung

Direkt nach dem Kurs eine kleine, aber echte Aufgabe belegen, die in vier bis sechs Wochen fertig wird und danach tatsächlich benutzt wird. Ein internes Kommandozeilenwerkzeug eignet sich dafür besser als ein Prototyp, den anschließend niemand betreibt.

Der Einstieg in fünf Stufen

  1. 01 Tage eins bis drei: Syntax, cargo und ein Programm, das etwas Sinnvolles ausgibt.
  2. 02 Woche eins: Datentypen, Option und Result, erste Fehlerbehandlung ohne unwrap.
  3. 03 Woche zwei: Der Borrow-Checker meldet sich, sobald Daten mehrere Stellen berühren.
  4. 04 Woche drei und vier: Eigene Strukturen entwerfen, statt gegen die Regeln zu schreiben.
  5. 05 Ab Woche fünf: Async, Traits und Generics, am besten anhand einer echten Aufgabe.
Was du mitnimmst

Was den Einstieg tatsächlich verkürzt

Der Unterschied zwischen vier und zwölf Wochen liegt selten an der Begabung, sondern an der Reihenfolge der Aufgaben, am Umgang mit den Fehlermeldungen und daran, ob jemand da ist, der dieselben Sackgassen schon durchlaufen hat.

Erst lesen und umformen, dann entwerfen

Fang mit Code an, der einer Pipeline folgt: Eingabe lesen, umformen, ausgeben. Dort ist das Eigentumsmodell fast unsichtbar, weil die Daten in eine Richtung fließen. Strukturen, in denen etwas auf etwas anderes zurückzeigt, verschiebst du bewusst nach hinten.

Die Fehlermeldung zu Ende lesen

Der Compiler nennt die Stelle, den Grund und oft einen konkreten Vorschlag, dazu einen Fehlercode. Mit rustc --explain und diesem Code bekommst du die lange Erklärung samt Beispiel. Das ist das eigentliche Lehrbuch, und die meisten überspringen es zugunsten der ersten Forensuche.

Klonen bewusst setzen, nicht reflexhaft

Ein clone beim Laden der Konfiguration kostet nichts und ist die richtige Antwort. Dasselbe clone in einer Schleife über eine Million Datensätze ist der Grund, warum die Rust-Fassung am Ende langsamer ist als die Python-Fassung davor. Entscheide mit Größe und Häufigkeit vor Augen.

Den Rhythmus auf cargo check umstellen

Cargo check prüft Typen und Ausleihen, ohne ein Programm zu erzeugen, und ist deutlich schneller als ein vollständiger Bau. Der Editor macht über rust-analyzer dasselbe fortlaufend. Cargo build gehört an die Stelle, an der du tatsächlich etwas ausführen willst.

Die Übersetzungszeit als Projektentscheidung behandeln

Eine Aufteilung in einen Workspace aus mehreren Crates sorgt dafür, dass eine Änderung nur ihr eigenes Paket und dessen Abhängige neu übersetzt. Für den Bindeschritt lässt sich ein schnellerer Linker eintragen. Beides ist einmalige Arbeit und wirkt danach jeden Tag.

Die erste Aufgabe klein und echt wählen

Ein Kommandozeilenwerkzeug, das im Team wirklich gebraucht wird, etwa ein Auswerter für Protokolldateien oder ein Migrationsskript. Klein genug, um fertig zu werden, echt genug, dass die Arbeit danach nicht weggeworfen wird.

KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt

Was aus welcher Sprache leicht und was schwer fällt

Aus Java oder C# kommend liest sich die Syntax vertraut. Die erste echte Umstellung ist die Fehlerbehandlung: Es gibt kein throw, das zehn Ebenen überspringt, der Fehler reist als Rückgabewert und wird mit dem Fragezeichen-Operator weitergereicht. Die eigentliche Hürde kommt danach, weil der Objektgraph, den die Speicherbereinigung bisher umsonst getragen hat, plötzlich eine Entwurfsentscheidung ist. Schnittstellen entsprechen ungefähr Traits, funktionieren aber anders, weil sich eine Implementierung auch außerhalb des Typs unterbringen lässt.

Aus Python kommend sind Typen überall, ein Übersetzungsschritt kommt dazu, und die Gewohnheit, kurz ein Wörterbuch zwischenzuschalten, funktioniert nicht mehr. Positiv fällt zweierlei auf: Cargo ist gegenüber der Paketlage in Python eine Erleichterung, und der Compiler fängt vieles ab, wofür bisher Tests zuständig waren.

Aus C++ kommend ist der Start am leichtesten und die Mitte am ärgerlichsten. RAII, Verschiebesemantik und Templates haben Entsprechungen, aber der Borrow-Checker setzt durch, was in C++ Konvention war. Die typische Reibung: Muster, die dort völlig üblich sind, etwa ein roher Zeiger in einen Container hinein oder eine Referenz auf ein Feld eines anderen Objekts, werden schlicht abgelehnt. Aus Go kommend ist die Fehlerbehandlung vertraut, async und Generics sind es nicht, und die Bauzeiten fallen unangenehm auf.

Die drei Stellen, an denen fast alle hängen bleiben

Die erste ist das Verschieben. Wenn du einen String an eine Funktion übergibst, geht der Besitz über, und die ursprüngliche Variable ist danach tot. Das ist die erste Überraschung, weil im Quelltext nichts davon steht und weil es bei Zahlen nicht passiert. Wer einmal verstanden hat, dass die Sprache zwischen Typen unterscheidet, die sich billig kopieren lassen, und solchen, die einen Besitzer haben, erkennt die Meldung ab dann sofort.

Die zweite ist das Ausleihen. Solange eine lesende Ausleihe lebt, gibt es keine veränderliche, und umgekehrt. Der klassische Auslöser ist eine Schleife über eine Sammlung, in deren Rumpf du dieselbe Sammlung änderst. Die Regel verhindert genau das, was in C++ zu ungültigen Iteratoren führt, wenn ein Vektor beim Wachsen umzieht, und dieser Zusammenhang macht sie für viele erst einleuchtend.

Die dritte sind Lebensdauern in Strukturen. In dem Moment, in dem du eine Referenz in ein Feld schreibst, will der Compiler eine Angabe dazu, und diese Angabe zieht sich anschließend durch jede Funktion und jeden Trait, in dem der Typ vorkommt. Die richtige Antwort ist für Einsteiger fast immer: keine Referenz speichern, sondern den Wert selbst. Ein String im Feld statt eines Ausschnitts kostet eine Speicheranforderung und erspart dir eine ganze Kategorie von Folgeproblemen.

Die Übersetzungszeit und was sie mit dem Lernen macht

Rust baut langsam, und das hat nachvollziehbare Gründe. Generischer Code wird für jeden konkreten Typ neu übersetzt, der Optimierer arbeitet gründlich, und am Ende steht der Bindeschritt, der bei einem großen Programm einen erheblichen Anteil ausmacht. Bei einem Projekt mit vielen Abhängigkeiten dauert der erste vollständige Bau entsprechend, und wer das nicht erwartet, hält es für einen Konfigurationsfehler.

Für das Lernen ist das ein echtes Hindernis, weil die Schleife aus Ändern, Ausführen und Hinsehen, die in Python funktioniert, hier nicht funktioniert. Der tragfähige Ersatz ist ein anderer Rhythmus: Der Editor prüft über rust-analyzer fortlaufend im Hintergrund, cargo check liefert im Terminal in Sekunden die Typ- und Ausleihprüfung, und ein vollständiger Bau steht erst an, wenn du wirklich etwas ausführen willst. Das klingt nach einer Kleinigkeit und entscheidet in der Praxis darüber, wie viele Versuche pro Stunde möglich sind.

Im Projekt helfen drei Dinge dauerhaft: die Aufteilung in einen Workspace, damit eine Änderung nur ihr eigenes Paket neu übersetzt, ein schlanker Abhängigkeitsbaum, weil jede Abhängigkeit mit übersetzt wird, und ein schnellerer Linker für den Bindeschritt. Ganz weg geht das Problem nicht. Es wird beherrschbar, und diese Unterscheidung sollte in jeder Planung stehen.

Wie ein Team den Einstieg abfedert, ohne den Termin zu verlieren

Nicht mit dem kritischen Bauteil anfangen. Das erste Rust-Stück sollte abgegrenzt sein und im Zweifel weggeworfen werden können. Und nie mit einer einzigen Person: Wer allein lernt, hat niemanden für ein Review, und der gesamte Code hängt danach an einem Kalender. Zu zweit kommt ihr spürbar schneller voran als eine Person allein, weil die meisten Borrow-Checker-Fragen Entwurfsfragen sind und sich im Gespräch in Minuten klären.

Die Konventionen gehören früh aufgeschrieben, und zwar bevor der erste Code entsteht: welche Bibliothek für Fehlertypen, welche Laufzeitumgebung für async, wann ein Klon in Ordnung ist, wann eine Funktion den Besitz übernimmt und wann sie ausleiht. Ohne diese Festlegungen beantwortet jedes Modul die Fragen anders, und die Codebasis wird schwer lesbar, lange bevor sie groß ist.

Zum Zeitpunkt eines Kurses gibt es eine Faustregel, die sich bewährt hat: Er wirkt besser nach zwei Wochen eigener Versuche als davor. Wer schon einmal gegen die Wand gelaufen ist, stellt andere Fragen und nimmt Antworten mit, für die es vorher keinen Anlass gab. Und die Aufgabe, an der danach weitergearbeitet wird, sollte vor dem Kurs feststehen, sonst verfällt der Stoff, bevor er zum Einsatz kommt.

Dazu passende Kurse

Weil erfahrungsgemäß die zweite Woche die unangenehme ist, spart ein begleiteter Einstieg in Rust genau dort die Tage, die sonst in der Fehlersuche versickern.

Wer bisher nie mit Stapel und Halde zu tun hatte, tut sich mit den Eigentumsregeln erkennbar schwerer, und dafür lohnt es sich, vorher Grundlagen der Softwareentwicklung aufzufrischen.

Wissen prüfen

Wie sicher bist du beim Thema wirklich?

Lesen fühlt sich schnell nach Können an. Ein kurzer Test zeigt dir, was davon schon sitzt und wo sich ein Kurs lohnt. Kostenlos, ohne Anmeldung, mit einer Erklärung zu jeder Antwort.

Konkrete Kurse

Wo du genau das übst

Sehr angenehmes, gut vorbereitetes Seminar, kann ich nur empfehlen.
Rust Fortgeschrittenenkurs

Häufige Fragen

Wie lange dauert es bis zur ersten produktiven Aufgabe?
Kompilierender Code entsteht in Tagen, eigenständige Entwürfe brauchen mehrere Wochen. Entscheidender als die Person ist dabei die Art der Aufgabe: Ein Werkzeug, das Daten in einer Richtung durchschleust, ist schnell fertig. Ein Dienst mit Zustand, auf den mehrere Stellen zugreifen, dauert deutlich länger, weil dort genau die Fragen aufschlagen, die neu sind.
Reicht ein zweitägiger Kurs?
Für Syntax, Eigentumsmodell, Option und Result sowie ein erstes lauffähiges Programm ja. Für die Entwurfsfragen nicht, weil die erst an deinen eigenen Daten auftauchen. Realistisch ist die Kombination: Kurs, danach eine kleine echte Aufgabe, und ein Review durch jemanden, der die üblichen Sackgassen kennt.
Kann jemand ohne C oder C++ Rust lernen?
Ja. Der Teil, der C++-Leuten am schwersten fällt, nämlich das Ablegen alter Zeigergewohnheiten, entfällt bei ihnen komplett. Was zusätzlich gebraucht wird, ist eine Vorstellung von Stapel und Halde und davon, was eine Kopie kostet, weil Rust genau das sichtbar macht, was andere Sprachen verstecken.
Was ist schwerer, der Borrow-Checker oder async?
Das hängt davon ab, was du baust. Für Kommandozeilenwerkzeuge und Stapelverarbeitung brauchst du async vielleicht nie. Für einen Netzwerkdienst ist async die zweite Wand, und sie ist für viele steiler, weil die Meldungen dort länger sind und Bedingungen an Traits enthalten, die man erst lesen lernen muss.
Persönlich für dich da

Deine Ansprechpartner

Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.

Yves Hoppe

Yves Hoppe

Weiterbildung & Beratung

Hilft dir, aus dem Rust-Programm den passenden Kurs für deinen Stand zu finden.

Norbert Jansen

Norbert Jansen

Beratung & Inhouse

Plant mit dir Inhouse-Trainings, die auf eure Abläufe und euren Datenbestand zugeschnitten sind.

Die ersten Wochen mit jemandem im Raum

Bei cmt machst du den Einstieg mit einem Trainer, der die üblichen Sackgassen kennt und dir sagt, ob dein Entwurf ein Rust-Problem hat oder einen Denkfehler enthält.