Rust
Result and commands
Split commands into functions that return Result.
Commands with Result
Let the command handler return each command's result as Result<String, String>: a message for the user on success, a description on error. Slice patterns let you match the arguments directly:
fn calistir(d: &mut Defter, args: &[&str]) -> Result<String, String> {
match args {
["ekle", metin @ ..] if !metin.is_empty() => {
d.ekle(metin.join(" "));
Ok(String::from("eklendi"))
}
["sil", n] => { /* parse n */ }
[k, ..] => Err(format!("bilinmeyen komut: {k}")),
[] => Err(String::from("komut yok")),
}
}
Deleting and validation
The delete command must parse the number and check it's in range. Instead of a bare ?, clear messages are produced with map_err:
["sil", n] => {
let i: usize = n.parse().map_err(|_| format!("geçersiz numara: {n}"))?;
if i == 0 || i > d.notlar.len() {
return Err(format!("böyle bir not yok: {i}"));
}
let silinen = d.notlar.remove(i - 1);
Ok(format!("silindi: {silinen}"))
}
Exercise Command handler
Write fn calistir(d: &mut Defter, args: &[&str]) -> Result<String, String>: handle ekle, sil and unknown commands as above. Print the results of ["ekle", "süt", "al"], ["sil", "x"] and ["uç"] with {:?} on separate lines.
Show example solution
struct Defter {
notlar: Vec<String>,
}
impl Defter {
fn new() -> Self {
Self { notlar: Vec::new() }
}
fn ekle(&mut self, metin: String) {
self.notlar.push(metin);
}
}
fn calistir(d: &mut Defter, args: &[&str]) -> Result<String, String> {
match args {
["ekle", metin @ ..] if !metin.is_empty() => {
d.ekle(metin.join(" "));
Ok(String::from("eklendi"))
}
["sil", n] => {
let i: usize = n.parse().map_err(|_| format!("geçersiz numara: {n}"))?;
if i == 0 || i > d.notlar.len() {
return Err(format!("böyle bir not yok: {i}"));
}
let silinen = d.notlar.remove(i - 1);
Ok(format!("silindi: {silinen}"))
}
[k, ..] => Err(format!("bilinmeyen komut: {k}")),
[] => Err(String::from("komut yok")),
}
}
fn main() {
let mut d = Defter::new();
println!("{:?}", calistir(&mut d, &["ekle", "süt", "al"]));
println!("{:?}", calistir(&mut d, &["sil", "x"]));
println!("{:?}", calistir(&mut d, &["uç"]));
}
Test yourself
-
In the pattern <code>["ekle", metin @ ..]</code>, what is <code>metin</code>?
- The number of elements
- The slice of all elements after "ekle"
- Only the second element
- The last element
Show answer
The slice of all elements after "ekle" — .. matches the remaining elements; with metin @, that part is bound as a slice.
-
Bind the rest
match args {
["ekle", metin @ ____] => Ok(metin.join(" ")),
_ => Err(String::from("?")),
}
Show answer
match args {
["ekle", metin @ ..] => Ok(metin.join(" ")),
_ => Err(String::from("?")),
}
-
Arguments and result
- ["ekle", "süt", "al"]
- Ok("eklendi")
- ["sil", "x"]
- Err("geçersiz numara: x")
- ["uç"]
- Err("bilinmeyen komut: uç")
- []
- Err("komut yok")
Next lesson: Processing with iterators