465 lines
17 KiB
Markdown
465 lines
17 KiB
Markdown
# Rust
|
||
Rust ist eine moderne Systemprogrammiersprache, die mit Fokus auf Performance, Speichersicherheit und Nebenläufigkeit entwickelt wurde. Sie ermöglicht es Entwicklern, zuverlässige und effiziente Software zu erstellen, von Betriebssystemen bis hin zu Webanwendungen.
|
||
|
||
## Hello World!
|
||
Das „Hello World!“ ist ein einfaches Programm, das Hello World! auf dem Bildschirm ausgibt.
|
||
|
||
In Rust verwenden wir das Makro `println!()`, um eine Ausgabe auf der Konsole auszugeben. Beachte, dass `println!` mit `ln` endet: einem Kleinbuchstaben l (wie in „line“), nicht mit einem Großbuchstaben I. Der auszugebende Text wird innerhalb doppelter Anführungszeichen platziert und in Klammern eingeschlossen.
|
||
|
||
Sehen wir uns das „Hello World!“-Programm in Rust an:
|
||
|
||
```rust
|
||
fn main() {
|
||
println!(„Hello World!“);
|
||
}
|
||
```
|
||
## Kommentare
|
||
|
||
**Comments** sind Notizen, die man in den Code schreibt. Der compiler ignoriert sie vollständig – sie existieren nur, um Menschen beim Verständnis des Codes zu helfen.
|
||
|
||
Um einen einzeiligen Kommentar zu schreiben, verwendet man `//`. Alles nach `//` bis zum Ende der Zeile wird ignoriert:
|
||
|
||
```rust
|
||
// Das ist ein Kommentarprintln!("Hello, world!");
|
||
```
|
||
|
||
Ein Kommentar kann auch am Ende einer Zeile nach dem Code geschrieben werden:
|
||
|
||
```rust
|
||
println!("Hello, world!"); // Dies gibt Hello, world! aus!
|
||
```
|
||
|
||
Für Kommentare, die sich über mehrere Zeilen erstrecken, verwendet man `/*`, um zu beginnen, und `*/`, um zu enden:
|
||
|
||
```rust
|
||
/* Dies ist ein mehrzeiliger Kommentar. Der Compiler ignoriert ihn vollständig. */println!("Welcome!");
|
||
```
|
||
|
||
Kommentare können eine Codezeile auch vorübergehend **deaktivieren**, ohne sie zu löschen:
|
||
|
||
```rust
|
||
// println!("This line will NOT run");println!("This line will run");
|
||
```
|
||
|
||
**Hinweis:** Jeder mehrzeilige Kommentar, der mit `/*` beginnt, muss mit `*/` geschlossen werden, andernfalls behandelt der Compiler alles danach als Kommentar.
|
||
|
||
Grundlegende Programmstruktur
|
||
|
||
In Rust beginnt jedes ausführbare Programm mit der Funktion `main`. Diese Funktion ist der Einstiegspunkt des Programms und dort beginnt die Ausführung.
|
||
|
||
Die `function` `main` wird mit dem Schlüsselwort `fn`definiert, gefolgt von `main` und einem Klammerpaar `()`. Der auszuführende Code wird innerhalb geschweifter Klammern `{}` platziert.
|
||
|
||
Hier ist eine einfache Aufschlüsselung eines grundlegenden Rust-Programms:
|
||
|
||
```rust
|
||
fn main() { // Hauptfunktion
|
||
println!("Hello, Coddy!"); // Ausgabeanweisung}
|
||
}
|
||
```
|
||
|
||
Wichtiger Hinweis: In Rust muss jede Anweisung mit einem Semikolon (`;`) enden. Das Semikolon ist obligatorisch und teilt Rust mit, dass du das Ende einer Anweisung erreicht hast.
|
||
|
||
Wenn du vergisst, ein Semikolon hinzuzufügen, führt dies zu einem Kompilierungsfehler. Beachte jedoch, dass Codeblöcke, die in geschweiften Klammern {} eingeschlossen sind (wie Funktionsdeklarationen), keine Semikolons benötigen.
|
||
|
||
## Grundlegende Programmstruktur
|
||
|
||
In Rust beginnt jedes ausführbare Programm mit der Funktion `main`. Diese Funktion ist der Einstiegspunkt des Programms und dort beginnt die Ausführung.
|
||
|
||
Die `function` `main` wird mit dem Schlüsselwort `fn`definiert, gefolgt von `main` und einem Klammerpaar `()`. Der auszuführende Code wird innerhalb geschweifter Klammern `{}` platziert.
|
||
|
||
Hier ist eine einfache Aufschlüsselung eines grundlegenden Rust-Programms:
|
||
|
||
```rust
|
||
fn main() { // Hauptfunktion
|
||
println!("Hello, Coddy!"); // Ausgabeanweisung
|
||
}
|
||
```
|
||
|
||
Wichtiger Hinweis: In Rust muss jede Anweisung mit einem Semikolon (`;`) enden. Das Semikolon ist obligatorisch und teilt Rust mit, dass du das Ende einer Anweisung erreicht hast.
|
||
|
||
Wenn du vergisst, ein Semikolon hinzuzufügen, führt dies zu einem Kompilierungsfehler. Beachte jedoch, dass Codeblöcke, die in geschweiften Klammern `{}` eingeschlossen sind (wie Funktionsdeklarationen), keine Semikolons benötigen.
|
||
|
||
## Zahlen
|
||
|
||
**Variablen** sind Container, die Datenwerte enthalten. Sie werden verwendet, um Informationen innerhalb eines Programms zu speichern, zu manipulieren und anzuzeigen.
|
||
|
||
Kurz gesagt ist eine Variable wie eine Speichereinheit, auf die wir zugreifen können, indem wir den Namen der Variable eingeben.
|
||
|
||
Jede Variable hat einen eindeutigen **Namen** und einen **Wert**, der von unterschiedlichem Typ sein kann. Rust verfügt über verschiedene integrierte Datentypen, die den Typ des Wertes definieren, den eine Variable enthalten kann.
|
||
|
||
Um eine Variable zu initialisieren, verwenden wir das folgende **Format**:
|
||
|
||
```rust
|
||
let variable_name: variable_type = value;
|
||
```
|
||
|
||
In Rust werden Zahlen normalerweise mit zwei Hauptdatentypen dargestellt: `i32` und `f64`.
|
||
|
||
`i32` wird verwendet, um ganze Zahlen ohne Dezimalpunkt zu speichern. Zum Beispiel:
|
||
|
||
```rust
|
||
let age: i32 = 30;
|
||
let temperature: i32 = -5;
|
||
let count: i32 = 100;
|
||
```
|
||
|
||
`f64` wird verwendet, um Zahlen mit einem Dezimalpunkt zu speichern. Zum Beispiel:
|
||
|
||
```rust
|
||
let price: f64 = 99.99;
|
||
let pi: f64 = 3.14159;
|
||
let fraction: f64 = 0.5;
|
||
```
|
||
|
||
Beim Deklarieren von Variablen in Rust müssen Sie den Typ der Variable nach dem Variablennamen angeben, gefolgt von einem Doppelpunkt. Dies wird als **Typdeklaration** bezeichnet. Sobald eine Variable mit einem bestimmten Typ deklariert wurde, kann sie nur Werte dieses Typs enthalten.
|
||
|
||
### Challenge
|
||
|
||
Schreiben Sie ein Rust-Programm, das die folgenden Variablen deklariert und initialisiert:
|
||
|
||
- Deklarieren Sie eine `i32`-Variable namens `quantity`und initialisieren Sie diese mit dem Wert `5`.
|
||
- Deklarieren Sie eine `f64`-Variable namens `item_price`und initialisieren Sie diese mit dem Wert `24.99`.
|
||
|
||
Nachdem Sie diese Variablen deklariert und initialisiert haben, verwenden Sie `println!()`, um die Werte der Variablen im folgenden Format auf der Konsole auszugeben:
|
||
|
||
```rust
|
||
Quantity: [value of quantity]
|
||
Price: [value of item_price]
|
||
```
|
||
|
||
#### Lösung:
|
||
```rust
|
||
fn main() {
|
||
// Variablen hier deklarieren und initialisieren
|
||
let quantity: i32 = 5;
|
||
let item_price: f64 = 24.99;
|
||
|
||
println!("Quantity: {}", quantity);
|
||
println!("Price: {}", item_price);
|
||
}
|
||
```
|
||
|
||
## Char
|
||
|
||
Ein **char** ist ein einzelnes Zeichen (Zum Beispiel: `1, 6, %, b, p, ., T`, etc.)
|
||
|
||
Der **char**-Typ ist ein spezieller Typ, der aus einem einzelnen Zeichen besteht.
|
||
|
||
Um einen char-Wert in einer Variablen zu initialisieren, schließen Sie ihn in **einfache Anführungszeichen** ein:
|
||
|
||
```rust
|
||
let c1: char = 'h';
|
||
```
|
||
|
||
Im obigen Beispiel wird eine char-Variable namens `c1`initialisiert.
|
||
|
||
## String
|
||
|
||
Ein **char** ist ein einzelnes Zeichen (Zum Beispiel: 1, 6, %, b, p, ., T, etc.)
|
||
|
||
Der Typ **String** ist ein spezieller Typ, der aus mehreren **char**s besteht.
|
||
|
||
Um einen String-Wert in einer Variablen zu initialisieren, schließen Sie ihn in **doppelte Anführungszeichen** ein:
|
||
|
||
```rust
|
||
let s1 = "This is a string";
|
||
```
|
||
|
||
Im obigen Beispiel wird eine String-Variable namens `s1` initialisiert.
|
||
|
||
Anders als bei Zahlen müssen wir bei der Arbeit mit Strings vorsichtiger mit Typen sein.
|
||
|
||
Wenn Sie explizit einen String-Typ deklarieren möchten, müssen Sie die Zeichenfolge wie folgt konvertieren:
|
||
|
||
```rust
|
||
let s1: String = "This is a string".to_string();
|
||
```
|
||
######################################################
|
||
<mark style="background:#ff4d4f">Rust unterscheidet zwischen String-Literalen und dem Typ String, was eine explizite Konvertierung erfordert.</mark> noch beschreiben
|
||
|
||
String-Literal --> normaler String a = "hhhh"
|
||
######################################################
|
||
### Challenge
|
||
|
||
Speichere den String `I am learning to code with Coddy!` in einer Variable namens `coddy` unter Verwendung eines String-Literals (mit doppelten Anführungszeichen)..
|
||
|
||
> Stelle sicher, dass du den **exakten** String-Wert mit korrekter Groß- und Kleinschreibung speicherst.
|
||
|
||
|
||
```rust
|
||
fn main() {
|
||
|
||
let coddy = "I am learning to code with Coddy!".to_string();
|
||
|
||
println!("coddy = \"{}\"", coddy);
|
||
|
||
}
|
||
```
|
||
|
||
## Boolean
|
||
|
||
Ein **boolescher** Typ hat nur 2 mögliche Werte: `true` oder `false`.
|
||
|
||
Um einer Variablen einen booleschen Wert zuzuweisen, verwenden Sie das Schlüsselwort `let` gefolgt vom Variablennamen:
|
||
|
||
```rust
|
||
let variable_true: bool = true;
|
||
let variable_false: bool = false;
|
||
```
|
||
|
||
Im obigen Beispiel werden zwei boolesche Variablen namens `variable_true` und `variable_false` jeweils mit den Werten `true` und `false` initialisiert.
|
||
|
||
> Booleans sind die Bausteine für die Erstellung von Logik in den Programmen, die wir schreiben. Wir haben ein ganzes Kapitel über Logik und Bedingungen.
|
||
|
||
## Veränderbare Variablen
|
||
|
||
In Rust sind Variablen standardmäßig unveränderlich. Das bedeutet, dass man einen Wert, sobald er einer Variablen zugewiesen wurde, nicht mehr ändern kann. Man kann eine Variable jedoch veränderlich machen, indem man bei der Deklaration der Variablen das Schlüsselwort `mut` verwendet.
|
||
|
||
Zum Beispiel:
|
||
|
||
```rust
|
||
let x = 5; // x ist unveränderlich
|
||
let mut y = 10; // y ist veränderlich
|
||
```
|
||
|
||
In diesem Beispiel ist `x` unveränderlich, sodass Sie seinen Wert nach der Initialisierung nicht mehr ändern können. Andererseits ist `y` veränderlich, sodass Sie seinen Wert später im Code ändern können.
|
||
|
||
```rust
|
||
y = 20; // Dies ist erlaubt, da y veränderbar ist
|
||
x = 15; // Dies wird einen Fehler verursachen, da
|
||
```
|
||
|
||
### Challenge
|
||
Deklariere eine veränderbare Variable namens `add` und weise ihr den Wert 13 zu.
|
||
|
||
Ändere den Wert von 13 auf 16.
|
||
### Lösung
|
||
```rust
|
||
#[allow(unused_assignments)]
|
||
|
||
fn main() {
|
||
// Variable add initialisieren
|
||
let mut add = 13;
|
||
|
||
// Wert von 13 auf 16 ändern
|
||
add = 16;
|
||
|
||
println!("add = {}", add);
|
||
}
|
||
```
|
||
|
||
## Typdeklaration
|
||
|
||
Sobald eine Variable mit einem bestimmten Typ deklariert wurde, kann sie nur Werte dieses Typs enthalten. Beispielsweise kann eine `i32`-Variable nur Ganzzahlwerte enthalten, und eine `String`-Variable kann nur Text enthalten.
|
||
|
||
Zum Beispiel:
|
||
|
||
```rust
|
||
let mut age: i32 = 25; // Kann nur ganze Zahlen speichern
|
||
let mut name: &str = "Alice"; // Kann nur Text speichern
|
||
```
|
||
|
||
Diese würden Fehler verursachen:
|
||
|
||
```rust
|
||
age = "Bob"; // Fehler: Text kann nicht in eine i32-Variable geschrieben werden
|
||
name = 30; // Fehler: Eine Zahl kann nicht in eine String-Variable geschrieben werden
|
||
```
|
||
|
||
Diese sind gültig:
|
||
|
||
```rust
|
||
age = 26; // OK: Zuweisen einer neuen Ganzzahl
|
||
name = "Jane"; // OK: Zuweisen einer neuen Textzeichenkette
|
||
```
|
||
|
||
### Challenge
|
||
Deklariere die folgenden Variablen mit ihren entsprechenden Typen und Werten:
|
||
|
||
- Eine `i32`-Variable namens `count` mit dem Wert `10`.
|
||
- Eine `f64`-Variable namens `total` mit dem Wert `150.75`.
|
||
- Eine `char`-Variable namens `grade` mit dem Wert `'A'`.
|
||
- Eine `bool`-Variable namens `is_active` mit dem Wert `false`.
|
||
- Eine `String`-Variable namens `user_name` mit dem Wert `"Bob123"`.
|
||
|
||
Verwende nach der Deklaration dieser Variablen `println!()`, um die Werte der Variablen im folgenden Format auf der Konsole auszugeben:
|
||
|
||
```rust
|
||
Count: [value of count]
|
||
Total: [value of total]
|
||
Grade: [value of grade]
|
||
Active: [value of is_active]
|
||
User Name: [value of user_name]
|
||
```
|
||
|
||
### Lösung
|
||
|
||
```rust
|
||
fn main() {
|
||
// Variablen hier deklarieren
|
||
let count: i32 = 10;
|
||
let total: f64 = 150.75;
|
||
let grade: char = 'A';
|
||
let is_active: bool = false;
|
||
let user_name: String = "Bob123".to_string();
|
||
|
||
println!("Count: {}", count);
|
||
println!("Total: {}", total);
|
||
println!("Grade: {}", grade);
|
||
println!("Active: {}", is_active);
|
||
println!("User Name: {}", user_name);
|
||
}
|
||
```
|
||
|
||
## Namenskonventionen
|
||
|
||
In Rust gibt es mehrere Benennungskonventionen, die Sie befolgen sollten, um Ihren Code lesbarer und wartbarer zu machen. Sie sind in der Rust-Community weitgehend akzeptiert.
|
||
|
||
Hier sind einige gängige Namenskonventionen:
|
||
|
||
- Variablen sollten mit `snake_case` benannt werden, was bedeutet, dass alle Buchstaben kleingeschrieben und Wörter durch Unterstriche getrennt werden. Zum Beispiel: `my_variable`, `calculate_total`.
|
||
|
||
- Vermeiden Sie zu kurze oder kryptische Namen. Wählen Sie aussagekräftige Namen, die den Zweck der Variable klar angeben.
|
||
|
||
- Namen können Buchstaben, Ziffern und Unterstriche enthalten.
|
||
|
||
- Namen müssen mit einem Buchstaben oder einem Unterstrich `_` beginnen.
|
||
|
||
- Einfache Zähler verwenden normalerweise einzelne Buchstaben wie `i`, `j`, obwohl es erwähnenswert ist, dass aussagekräftigere Namen besser sein könnten, wenn der Kontext komplexer ist.
|
||
|
||
## Typinferenz
|
||
|
||
In Rust ermöglicht die Typinferenz dem Compiler, den Typ einer Variablen basierend auf ihrem Wert und ihrer Verwendung automatisch abzuleiten. Das bedeutet, dass Sie den Typ beim Deklarieren einer Variablen oft nicht explizit angeben müssen, was Ihren Code prägnanter und leichter lesbar macht.
|
||
|
||
Zum Beispiel:
|
||
|
||
```rust
|
||
let x = 5;// Rust leitet ab, dass x ein i32 ist
|
||
let y = 3.14;// Rust leitet ab, dass y ein f64 ist
|
||
let message = "Hello, world!";// Rust leitet ab, dass message ein &str (String) ist
|
||
let is_true = true;// Rust leitet ab, dass is_true ein bool ist
|
||
```
|
||
|
||
In diesen Beispielen haben wir die Typen von `x`, `y`, `message` und `is_true` nicht angegeben. Der Rust-Compiler hat ihre Typen automatisch basierend auf den ihnen zugewiesenen Werten abgeleitet.
|
||
|
||
Typinferenz ist nicht nur praktisch, sondern hilft auch dabei, Fehler zu vermeiden. Der Compiler prüft, wie die Variablen verwendet werden, und stellt sicher, dass die abgeleiteten Typen im gesamten Code konsistent sind. Wenn ein Konflikt auftritt, erzeugt der Compiler eine Fehlermeldung.
|
||
### Challenge
|
||
|
||
Schreibe ein Rust-Programm, das Typinferenz demonstriert. Deklariere und initialisiere die folgenden Variablen ohne explizite Typanmerkungen:
|
||
|
||
- Eine Variable namens `quantity` mit dem Wert `10`.
|
||
- Eine Variable namens `price` mit dem Wert `99.99`.
|
||
- Eine Variable namens `message` mit dem Wert `"Coddy is awesome!"`.
|
||
- Eine Variable namens `is_available` mit dem Wert `true`.
|
||
|
||
Verwende nach der Deklaration dieser Variablen `println!()`, um ihre Werte auf der Konsole auszugeben. Beobachte, wie Rust die Typen dieser Variablen basierend auf ihren Werten ableitet.
|
||
|
||
### Lösung
|
||
|
||
```rust
|
||
fn main() {
|
||
// Variablen hier deklarieren
|
||
let quantity = 10;
|
||
let price = 99.99;
|
||
let message = "Coddy is awesome!";
|
||
let is_available = true;
|
||
|
||
// Die Werte ausgeben
|
||
println!("Quantity: {}", quantity);
|
||
println!("Price: {}", price);
|
||
println!("Message: {}", message);
|
||
println!("Is available: {}", is_available);
|
||
}
|
||
```
|
||
|
||
## Typumwandlung
|
||
|
||
Typumwandlung bezeichnet den Vorgang, einen Wert von einem Datentyp in einen anderen umzuwandeln. In Rust verwenden wir das Schlüsselwort <mark style="background:#40a9ff">`as`</mark> für eine explizite Typumwandlung (auch als Typkonvertierung bezeichnet).
|
||
|
||
Die häufigsten Typumwandlungen finden zwischen numerischen Typen statt:
|
||
|
||
```rust
|
||
// Umwandlung von Integer zu Float
|
||
let number: i32 = 5;
|
||
let decimal: f64 = number as f64;// wird zu 5.0
|
||
```
|
||
|
||
```rust
|
||
// Umwandlung von Gleitkommazahl in Ganzzahl
|
||
let decimal: f64 = 9.7;
|
||
let number: i32 = decimal as i32;// wird zu 9 (Dezimalteil wird abgeschnitten)
|
||
```
|
||
### Challenge
|
||
Schreiben Sie ein Rust-Programm, das Typumwandlung demonstriert. Führen Sie die folgenden Operationen aus:
|
||
|
||
1. Deklarieren Sie eine `f64`-Variable namens `price` und initialisieren Sie diese mit dem Wert `99.99`.
|
||
2. Wandeln Sie die Variable `price` in einen `i32` um und speichern Sie das Ergebnis in einer neuen Variable namens `int_price`.
|
||
3. Geben Sie die Werte von `price` und `int_price` auf der Konsole aus.
|
||
|
||
```rust
|
||
fn main() {
|
||
// Variablen deklarieren und initialisieren
|
||
let price: f64 = 99.99;
|
||
let int_price: i32 = price as i32;
|
||
|
||
// Die Werte ausgeben
|
||
println!("Price: {}", price);
|
||
println!("Int Price: {}", int_price);
|
||
}
|
||
```
|
||
## Arithmetische Operatoren
|
||
|
||
**Operatoren** werden verwendet, um Operationen auf Werten auszuführen.
|
||
|
||
Zuerst werden wir die grundlegendsten **arithmetischen Operatoren** besprechen; sie sind Ihnen vielleicht aus dem Mathematikunterricht bekannt.
|
||
|
||
| Operator | Operation | Beispiel |
|
||
| -------- | -------------- | --------- |
|
||
| + | Addition | 3 + 2 = 5 |
|
||
| - | Subtraktion | 3 - 2 = 1 |
|
||
| * | Multiplikation | 3 * 2 = 6 |
|
||
| / | Division | 4 / 2 = 2 |
|
||
|
||
Sehen wir uns ein Verwendungsbeispiel an,
|
||
|
||
```rust
|
||
let a: i32 = 3;
|
||
let b: i32 = 5;
|
||
let c: i32 = a + b// c enthält 8
|
||
```
|
||
|
||
Beim Arbeiten mit Dezimalzahlen in Rust verwenden wir den Datentyp f64, der Zahlen mit Nachkommastellen speichern kann. Die gleichen arithmetischen Operatoren (+, -, *, /) funktionieren mit f64 genauso wie mit Ganzzahlen:
|
||
|
||
```rust
|
||
let x: f64 = 3.3;
|
||
let y: f64 = 4.1;
|
||
let z: f64 = x + y;// z enthält 7.4
|
||
```
|
||
### Challenge
|
||
|
||
Schreibe einen Code, der zwei Variablen, `a` und `b`, mit den Werten `5.2` und `2.6` (in dieser Reihenfolge) initialisiert.
|
||
|
||
Initialisiere danach eine weitere Variable `c`, die das Ergebnis von `a / b` enthalten wird.
|
||
|
||
```rust
|
||
fn main() {
|
||
// Schreibe deinen Code unten
|
||
let a: f64 = 5.2;
|
||
let b: f64 = 2.6;
|
||
let c: f64 = a / b;
|
||
|
||
// Ändere die folgende Zeile nicht
|
||
println!("a = {}, b = {}, c = {}", a, b, c);
|
||
}
|
||
```
|
||
|
||
|
||
https://rust-lernen.de/blog/zeichenketten.html
|
||
|
||
https://www.reddit.com/r/rust/comments/13wzjoq/media_difference_between_string_str_and_string/?tl=de#lightbox
|
||
|
||
https://cheats.rs/#pointer-meta
|
||
|
||
https://rust-lang-de.github.io/rustbook-de/title-page.html
|
||
|