Vibe Engines
YouTube

Lesson 7.1 · 8 min

Operations that can fail: Result

Someone types "/last two" instead of "/last 2". Chatterbox cannot turn "two" into a number, and it must say so instead of crashing. Rust makes "this might fail" part of the answer itself.

Adds to ChatterboxParse a command safely.

An answer or a reason

Chatterbox is about to get a /last 3 command: show the last three messages. The "3" arrives as text, so the program has to turn text into a number. That can fail, because the person might type /last two or /last -1 or /last and nothing else.

Some languages handle this by throwing an exception that flies up the program until something catches it. Rust has no exceptions. Instead, a function that can fail returns a value of a type called Result. It is an enum (lesson 5.3) with exactly two variants:

  • Ok(value): it worked, and here is the value.
  • Err(reason): it did not work, and here is why.

The type is written Result<T, E>: T is the kind of value you get on success, E is the kind of reason you get on failure. Turning text into a u32 returns Result<u32, ParseIntError>.

parse gives back a Result, not a number
fn main() {
let good = "3".parse::<u32>();
let bad = "three".parse::<u32>();
println!("{:?}", good);
println!("{:?}", bad);
}
$ cargo run
Ok(3)
Err(ParseIntError { kind: InvalidDigit })

One new piece of notation: {:?} inside println! prints a value in its debug form, the form meant for programmers, which shows Ok(3) or Err(...) with the variant name. Plain {} is for text meant for people. Standard library types such as Result already know how to print themselves this way.

PredictWhich one is it?
fn main() {
let r = "-1".parse::<u32>();
println!("{}", r.is_ok());
}

What does this print?

  • true
  • false
  • -1
Reveal the answer

The program prints: false A u32 cannot be negative, so "-1" is not a valid u32 and you get an Err. is_ok() asks "is it the Ok variant?" and the answer is no.

You cannot ignore it

Here is the part that makes Rust different. A Result is not a number. You cannot add to it or print it as a count. To get at the value inside you must say what to do in both cases, and the tool for that is match from lesson 3.2. Try to cover only the happy case and the compiler stops you.

Only handling Ok
fn main() {
let r = "3".parse::<u32>();
match r {
Ok(n) => println!("count is {n}"),
}
}
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
 --> src/main.rs:3:11
  |
3 |     match r {
  |           ^ pattern `Err(_)` not covered
  |
note: `Result<u32, ParseIntError>` defined here
 --> /rustc/b940084d7eb6a299eb4bfeb8e34901bc051e7ac4/library/core/src/result.rs:558:0
 ::: /rustc/b940084d7eb6a299eb4bfeb8e34901bc051e7ac4/library/core/src/result.rs:567:4
  |
  = note: not covered
  = note: the matched value is of type `Result<u32, ParseIntError>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
  |
4 ~         Ok(n) => println!("count is {n}"),
5 ~         Err(_) => todo!(),
  |

The message says a pattern is not covered: Err(_). That is the whole safety idea. A failure that nobody wrote code for is a compile error, not a surprise at 2 a.m.

Chatterbox gets /last

Here is the new function in context. parse_count trims spaces and parses. The loop tries two arguments, one good and one bad, and match handles both. (saturating_sub is subtraction that stops at zero, so asking for ten messages when there are three does not underflow. n as usize converts the u32 count into a usize, the type of a list length; as changes one number type into another.) The Message is the same one from chapter 6, with an author and a text.

Chatterbox v0.7 so far: /last with a Result
use std::num::ParseIntError;
 
struct Message {
author: String,
text: String,
}
 
fn parse_count(arg: &str) -> Result<u32, ParseIntError> {
arg.trim().parse::<u32>()
}
 
fn main() {
let history = vec![
Message { author: String::from("sam"), text: String::from("hi") },
Message { author: String::from("bot"), text: String::from("hello!") },
Message { author: String::from("sam"), text: String::from("what is a token?") },
];
for arg in ["2", "two"] {
match parse_count(arg) {
Ok(n) => {
println!("/last {arg}: showing {n}");
let skip = history.len().saturating_sub(n as usize);
for m in &history[skip..] {
println!(" {}: {}", m.author, m.text);
}
}
Err(e) => println!("/last {arg}: {e}"),
}
}
}
$ cargo run
/last 2: showing 2
  bot: hello!
  sam: what is a token?
/last two: invalid digit found in string
Try itYour turn: a count that never crashes

Write count_or_default. It parses arg as a u32 and returns it. If parsing fails it returns default instead. Use match on the Result.

Write count_or_default. It parses arg as a u32 and returns it. If parsing fails it returns default instead. Use match on the Result.

fn count_or_default(arg: &str, default: u32) -> u32 {
// parse arg, then match on Ok and Err
0
}
 
fn main() {
println!("{}", count_or_default("3", 5));
println!("{}", count_or_default("three", 5));
}

Hidden tests (4): good_number bad_text_uses_default negative_uses_default spaces_are_fine

This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.

What you have now

Chatterbox can read a count from the user and survive a bad one. The failure is a value you can match on, print, or turn into a friendlier message. Coming up, as a preview: the very next lesson shows how to pass a failure up to the caller in a single character, so you do not write a match at every step.

Self-check

Say it out loud, then reveal

Self-checkRetrieval beats re-reading
What are the two variants of Result<T, E>?Reveal
Ok(T) for success carrying the value, and Err(E) for failure carrying the reason.
Why does Rust refuse a match that only covers Ok?Reveal
Because the Err case would be silently unhandled. A failure nobody wrote code for becomes a compile error.
Does Rust throw exceptions?Reveal
No. A function that can fail returns a Result and the caller decides what to do.

That is lesson 7.1. Tick it off so the course remembers where you are.

Next: 7.2 The ? operator →
Learn Rust by building a chat app · Lesson 7.1 · every compiler message above is real output from rustc 1.99.0 (b940084d7 2026-09-28) (edition 2024) · Vibe Engines · 2026