Erste Schritte mit Rust

Vor ein paar Tagen wollte ich die Programmiersprache Rust ausprobieren. Bei Rust handelt es sich um eine Sprache, welche syntaktisch stark an C angelehnt ist und besonderes Augenmerk auf Sicherheit legt. Die erste Frage, die sich mir stellte, ist, ob es für Rust, eine vernünftige IDE-Unterstützung existiert. Fündig geworden bin ich bei IntelliJ IDEA, welches nach Installation des Rust-Plugins zur Programmierung in der Sprache genutzt werden kann. Debugging von Rust-Programmen wird aus technischen Gründen nur in der JetBrains IDE CLion unterstützt, sodass hier einige Abstriche gemacht werden müssen. Neben der Rust-Integration für IntelliJ IDEA gibt es ebenfalls ein Plugin für Visual Studio Code, welches hier allerdings nicht weiter behandelt werden soll.

Mit dem passenden Plugin beherrscht IntelliJ IDEA Rust.

Neben der eigentlichen IDE wird Rust benötigt. Dieses kann über die offizielle Seite der Sprache bezogen werden. Nach der Installation kann in der IDE ein erstes Projekt angelegt werden. Anschließend findet sich in einem Ordner mit dem Namen src eine Datei mit dem Namen main.rs:

fn main() {
    println!("Hello, world!");
}

In dieser Datei findet sich ein minimales Hello world-Programm. Das Ausrufezeichen hinter dem println zeigt unter Rust an, das es sich um ein Makro handelt. Damit können Methoden und Makros einfach auseinander gehalten werden. Da ich Hello world-Programme immer etwas sinnfrei finde was das Lernen einer neuen Programmiersprache angeht, wollte ich für den ersten Versuch das Spiel Zahlenraten programmieren. Ziel des Spieles ist es eine Zahl zwischen 0 und 1000 zu erraten, welche der Rechner sich ausgedacht hat. Dazu muss im ersten Schritt eine Variable definiert werden, in welcher die zufällige Zahl gespeichert wird. Grundsätzlich sieht eine Variablendefinition und Deklaration unter Rust wie folgt aus:

let name: Typ = Wert;

Variablen in Rust sind immer Konstanten, wenn sie nicht explizit als veränderlich angegeben werden. Möglich ist dies mit dem Schlüsselwort mut:

let mut name: Typ = Wert;

Die Benennung von Variablen und anderen Elementen folgt in Rust einem bestimmten Schema. So werden Variablen snake_case benannt. Neben der Definition der Variable muss eine zufällige Zahl zwischen 0 und 1000 generiert werden. Dazu dient ein Zufallsgenerator, welcher über ein use eingebunden werden muss:

use rand::Rng;

Anschließend kann die Variable definiert und deklariert werden:

let number: u32 = rand::thread_rng().gen_range(0, 1000);

In diesem Fall wird ein vorzeichenloser Integer mit 32 Bit Breite als Datentyp definiert. Wird nun versucht das Rust-Programm zu kompilieren, so wird die Fehlermeldung:

error[E0432]: unresolved import `rand`
 --> src\main.rs:1:5
  |
1 | use rand::Rng;
  |     ^^^^ use of undeclared type or module `rand`

error[E0433]: failed to resolve: use of undeclared type or module `rand`
 --> src\main.rs:4:23
  |
4 |     let number: u32 = rand::thread_rng().gen_range(0, 1000);
  |                       ^^^^ use of undeclared type or module `rand`

error: aborting due to 2 previous errors

auftauchen. Grund hierfür ist, dass das genutzte Paket über den Paketmanager von Rust bezogen werden muss. Pakete werden über den Paketmanager Cargo bezogen. Die entsprechenden Pakete des offiziellen Repositorys sind unter crates.io zu finden. In der Datei Cargo.toml müssen die entsprechenden Abhängigkeiten eingebunden werden:

[dependencies]
rand = "0.7.3"
text_io = "0.1.8"

Neben dem Pseudozufallszahlengenerator, wurde gleich noch das Paket text_io eingebunden, welches später für die Eingabe von Text benötigt wird. Dieses Paket stellt hierbei das Makro read zur Verfügung, mit dessen Hilfe eine Eingabe realisiert werden kann:

let user_number: u32 = read!();

Damit sind die Grundlagen für das Spiel Zahlenraten gelegt und der Rest des Quellcodes ergibt praktisch sich von selbst:

use rand::Rng;
use text_io::read;

fn main() {

    let number: u32 = rand::thread_rng().gen_range(0, 1000);

    let mut running = true;

    println!("Ich habe mir eine Zahl zwischen 0 und 1000 ausgedacht.");

    while running {

        println!("Dein Vorschlag: ");
        let user_number: u32 = read!();

        if number > user_number {
            println!("Meine Zahl ist größer.");
        } else if number < user_number {
            println!("Meine Zahl ist kleiner.");
        } else {
            running = false;
        }
    }

    println!("Du hast die Zahl erraten. Es war die {}.", number);
}

Hervorzuheben ist, das unter Rust in if-Statements und Schleifen keine Klammern benötigt werden. Werden diese trotzdem genutzt, so warnt der Compiler entsprechend und bittet die überflüssigen Klammern zu entfernen.

Neben der entsprechenden Dokumentation auf der offiziellen Seite empfiehlt sich das Rust Cookbook als Quelle für die ersten Schritte unter Rust. Wer Rust einfach mal im Browser ausprobieren möchte, kann hierfür den Rust Playground nutzen.

IntelliJ IDEA kompiliert über Maven

Normalerweise kompiliert die Java-IDE IntelliJ IDEA den Quelltext sobald, der Build-Vorgang gestartet wird. Allerdings kann es vorkommen das stattdessen jedes Mal der Kompiliervorgang über Maven angestoßen wird. Verantwortlich hierfür ist eine Einstellung der IDE.

Nachdem die Option deaktiviert wurde, kompilierte die IDE den Quellcode wieder

Zu finden ist diese Einstellung im Einstellungsdialog unter dem Punkt Build, Execution, Deployment -> Build Tools -> Maven- Runner. Dort existiert der Punkt Delegate IDE build/run actions to Maven. Wird dieser Punkt deaktiviert, ist die IDE wieder für die Kompilierung und den Build-Prozess verantwortlich.

Schriftgröße unter IntelliJ IDEA dynamisch anpassen

In der IDE IntelliJ IDEA von JetBrains kann die Schriftgröße für den Editor, wie gewünscht eingestellt werden. In manchen Fällen soll die Schriftgröße allerdings dynamisch eingestellt werden. Ein solcher Fall ist z.B. der Präsentationsmodus. In diesem Modus wird der Editor im Vollbild-Modus dargestellt und dient so der Präsentation des Quellcodes.

Das Einstellungsfenster von IntelliJ IDEA

Sollen hier die Zeilen, je nach Anforderung, nun größer oder kleiner dargestellt werden, kann dies über eine Option in den Einstellungen erreicht werden. In den Einstellungen findet sich unter Editor -> General der Punkt Change font size (Zoom) with Command+Mouse Wheel. Auf anderen Betriebssystemen wird statt der Command-Taste die Ctrl-Taste genutzt. Wird diese Option aktiviert, kann die Größe der Schriftart, in Verbindung mit der Command-Taste, dynamisch über das Mausrad eingestellt werden.

Code-Formatierung unter IntelliJ IDEA selektiv deaktivieren

IntelliJ IDEA bietet, wie wahrscheinlich jede brauchbare IDE, eine Funktionalität um den Quelltext automatisch zu formatieren. Manchmal kann es allerdings notwendig sein die Funktionalität für bestimmte Dateien oder Abschnitte zu deaktivieren. IntelliJ IDEA bietet dem Nutzer eine Möglichkeit dies zu tun. Dazu muss in den Einstellungen unter Code Style im Tab Formatter Control das entsprechende Feature aktiviert werden. Im Beispiel sieht das Ganze wie folgt aus:

// @formatter:off
try {
  // Do something wrong
} catch(Exception e) {
  // Gotta Catch 'Em All
}
// @formatter:on

Durch den einleitenden Kommentar @formatter:off wird die Code-Formatierung deaktiviert; am Ende des Blockes wird er mittels @formatter:on wieder aktiviert. Damit ist es mögliche Abschnitte und Dateien von der Code-Formatierung auszunehmen.

Probleme bei der Testausführung unter IntelliJ IDEA

Bei der Ausführung bestimmer Testfälle mittels JUnit kann es unter IntelliJ IDEA zu folgender Fehlermeldung kommen:

Error running ‘ConverterTest’: Command line is too long. Shorten command line for ConverterTestor also for JUnit default configuration.

Hintergrund für diesen Fehler ist das Problem, das die Kommandozeile zur Ausführung des Tests zu lang wird. Dies kann durch Beschränkungen des Betriebssystems passiere. IntelliJ IDEA versucht nun die Kommandozeile zu kürzen, um eine Ausführung zu ermöglichen.

Über die Konfiguration kann der Fehler behoben werden

Behoben werden kann das Problem über die Konfiguration des Testes. Dazu sollte der Run/Debug Configuration-Dialog geöffnet werden. Dort sollte im Tab Configuration unter dem Punkt Shorten command line der Punkt JAR manifest ausgewählt werden. Anschließend sollte der Test ohne Probleme durchgeführt werden können.