Erstes Spiel
Projekt erstellen
Das Projekt wird wie in den vorherigen Einträgen beschrieben erstellt.
Einen Input aufnehmen
use std::io;
println!("Guess the number!");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
println!("You guessed: {}", guess);
Ausgabe:
Guess the number!
Please input your guess.
Number? 42
You guessed: 42
Was haben wir gemacht?
use std::io;
bindet die Standard-IO Bibliothek einlet mut guess
legt eine Variableguess
anmut
bedeutet, dass sie “mutable” also veränderbar ist
String::new()
erstellt eine neue Instanz derString
-Klasseio::stdin()
legt einStdin
-Objekt an - ein Handler für die CLI-Eingabe- ohne die “use” Anweisung oben, müsste es
std::io::stdin()
sein
- ohne die “use” Anweisung oben, müsste es
.read_line(&mut guess)
ließt eine Zeile und speichert sie in guess&
erstellt dabei eine Referenz (wie in C)- Referenzen sind standardmäßig immutable - deshalb
&mut
read_line()
gibt einResult
-Objekt zurück, dieser kannOk
oderErr
enthalten
.expect("Fehlermeldung")
entpackt dasResult
-Objekt- Theoretisch ist das unnötig, sonst gibt es aber eine Warnung
- Sollte ein
Err
im Result sein, wird durchexpect()
eine Exception auftreten
println!("Eingabe: {}", guess)
ist ein formatiertes print
Eine random Zahl erstellen
Für eine random Zahl brauchen wir die erste Dependency. +
Also Cargo.toml
bearbeiten:
[dependencies]
rand = "0.3.14"
Dependencies findet man auch auf crates.io.
Die crate rand
kann jetzt im Code verwendet werden.
extern crate rand;
use rand::Rng;
let secret_number: u32 = rand::thread_rng().gen_range(1, 101);
println!("{}", secret_number);
Und schwubbs wird eine zufälle Zahl ausgegeben.
Höher oder tiefer?
Vergleichen wir doch einfach mal… Aber was ist das? Ein Fehler??
use std::cmp::Ordering;
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
Der Compiler sagt uns dann Folgendes:
match guess.cmp(&secret_number) {
^^^^^^^^^^^^^^ expected struct `String`, found `u32`
mismatched types
Unser guess
ist ja ein String
! Den kann man nicht einfach mit einem
int
vergleichen (anscheinend).
Wir müssen unser guess also umwandeln:
let guess: u32 = guess.trim().parse().expect("Please type a number!");
.strip()
entfernt Whitespace von beiden Seiten und parse()
macht
eine Zahl draus.
guess
als Variable ist schon vorhanden? Kein Problem! Rust erlaubt
“Shadowing”, damit man nicht mehrere Variablen unterschiedlicher
Datentypen für den selben Wert anlegen muss.
Jetzt sollte das Vergleichen auch klappen!
use std::cmp::Ordering;
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
Too big!
Wuuh!
Nicht nur ein Versuch
Damit wir mehrmals raten können, brauchen wir eine Schleife.
let secret_number: u32 = rand::thread_rng().gen_range(1, 101);
loop {
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
Number? 100
Too big!
Number? 50
Too big!
Number? 25
Too small!
Number? 30
Too small!
Number? 40
Too small!
Number? 42
Too small!
Number? 45
You win!
Number? 45
You win!
Number? 100
Too big!
Number? 45
You win!
Number?
…
Funktioniert, aber selbst nach dem Erraten passiert nichts und wir sollen weiter raten. Offensichtlich müssen wir die Schleife noch abbrechen.
let secret_number: u32 = rand::thread_rng().gen_range(1, 101);
loop {
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
},
}
}
Number? 100
Too big!
Number? 50
Too big!
Number? 25
Too small!
Number? 42
Too big!
Number? 39
Too big!
Number? 37
Too big!
Number? 36
Too big!
Number? 33
Too big!
Number? 30
Too big!
Number? 29
You win!
Error handling
Derzeit stirbt das Programm einfach mit einem Fehler, wenn man keine Zahl eingibt. Das können wir auch relativ einfach fixen:
loop {
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
// Wenn wir hier her kommen, haben wir eine gültige Zahl und beenden einfach.
break;
}
Number? a
Number? b
Number? 🦀
Number? 5
Statt einem expect()
haben wir nun eine match
-Expression. Die Syntax
ist relativ einfach zu verstehen. Man kann auch mehrere Ok(value)
nutzen, wobei dann das richtige aufgerufen wird. Err(_)
nutzt den
Unterstrich, um alle Fehler zu catchen, nicht nur einen speziellen.
Das num
nach dem Pfeil ist ein implizites Return. Wenn eine Variable
am Ende eines Blocks steht, wird sie zurückgegeben.
Fertig
Wir haben nun alle Elemente für das “Higher-Lower-Game”.