liveBook · Manning

Panic

As explained in Refactoring to Rust

A panic is Rust's runtime mechanism for signaling an unrecoverable error or violated assumption.

A panic signals that execution should not continue normally. Use panic! when an assumption has been violated or an error is unrecoverable. It unwinds the current thread’s stack; a panic in the only main thread exits the program with an error, while a panic in a background thread exits that thread. section 2.5.6

A failing operation need not cause a panic. Rust’s Result holds either a success value or an error value. A caller can handle the error, retry, or return it with ?. Choose a panic when the caller should not continue rather than as the default response to every error. section 2.5.6 section 2.6

Three ways to panic when a Result contains an error:

  • Match the Err variant and call panic! with a message specific to the failure. section 2.5.6
  • Call .unwrap() to use the success value or panic on an error. The error type must support Debug so the panic can display it. section 2.5.6
  • Call .expect("context") for the same choice with a message that identifies what failed. section 2.5.6

A negative FizzBuzz input

If fizzbuzz(-1) returns Err(Error::GotNegative), print_fizzbuzz can match that error and panic with the input value. Replacing the match with fizzbuzz(x).unwrap() is shorter, but requires Error to derive Debug and reports the error value instead of the tailored message. .expect("Failed to run fizzbuzz") adds context without restoring the match. section 2.5.6

Listing 2.37 Panicking when print_fizzbuzz sees an error
enum FizzBuzzValue {
  Fizz,
  Buzz,
  FizzBuzz,
  NotDivisible(i32),
}

enum Error {
  GotNegative,
}

fn main() {
  print_fizzbuzz(-1);  #1
}

fn print_fizzbuzz(x: i32) {  #2
  match fizzbuzz(x) {
    Ok(result) => match result {
      FizzBuzzValue::FizzBuzz => {
        println!("FizzBuzz");
      }
      FizzBuzzValue::Fizz => {
        println!("Fizz");
      }
      FizzBuzzValue::Buzz => {
        println!("Buzz");
      }
      FizzBuzzValue::NotDivisible(num) => {
        println!("{}", num);
      }
 #3
    },
    Err(Error::GotNegative) => {
      panic!("Got a negative number for fizzbuzz: {}", x);
    }
  }
}

fn fizzbuzz(x: i32) -> Result<FizzBuzzValue, Error> {
  if x < 0 {
    Err(Error::GotNegative)
  } else if x % 3 == 0 && x % 5 == 0 {
    Ok(FizzBuzzValue::FizzBuzz)
  } else if x % 3 == 0 {
    Ok(FizzBuzzValue::Fizz)
  } else if x % 5 == 0 {
    Ok(FizzBuzzValue::Buzz)
  } else {
    Ok(FizzBuzzValue::NotDivisible(x))
  }
}

The full FizzBuzz listing shows the explicit Err branch that calls panic! instead of returning an error. section 2.5.6

A panic message identifies where the panic occurred. Set RUST_BACKTRACE=1 when running the program to see the call stack; backtraces are not shown by default. In tests, assert! and assert_eq! panic on failed checks, and the test framework catches the panic and marks that test as failed. .unwrap() and .expect() can likewise make a test fail when an operation returns an error. section 2.5.6 section 7.1

How Refactoring to Rust covers it

How deep it goes
Explains thread-level unwinding, Result methods, error formatting, and backtrace activation through worked examples; does not detail unwinding internals.
Examples
Contrasts explicit panic!, .unwrap(), and .expect() on a negative FizzBuzz input, then shows a failing equality assertion.
What it assumes
Introduces panic! alongside Result and error handling, without requiring prior knowledge of Rust’s panic macro.
What you can do after
Apply panic! or Result methods when execution must stop, and diagnose a panic with its message and an enabled backtrace.
How it connects
Connects panic to Result, error propagation with ?, Debug, backtraces, assertions, and unit tests.

Also explained in

Compare how 8 books explain panic →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.