ProgramGuru

Validation, panic and checked access

Validation, panic and checked access

A program can encounter expected bad input or a violation of an internal assumption. Validation handles the former; panic reports an unrecoverable failure for the current operation. Choosing between them should depend on the contract, not on which spelling is shortest.

What you’ll learn

  • Choose checked access for expected missing data.
  • Separate recoverable input errors from invariant failures.

Validation, panic and checked access in action

  1. Prepared marks pass invariant

    The two marks satisfy the asserted range.

    Prepared marks pass invariant
  2. Position 2 is absent

    Index two is outside this two-element collection, so get reports None and the match prints a useful message.

    Position 2 is absent
  3. Handle absence visibly

    It avoids direct indexing that would panic.

    Handle absence visibly
The two marks satisfy the asserted range. Index two is outside this two-element collection, so get reports None and the match prints a useful message. It avoids direct indexing that would panic.

Validation, panic and checked access explained

assert! checks an assumption and panics when it is false. get handles an uncertain collection position through Option. expect adds a message but still panics on failure. Use Result or Option when callers are expected to recover, and reserve assertions for invariants that should hold after validation.

Work through the Rust program

Save the complete source as main.rs in the Rust environment. No standard input is needed.

Rust 2024 · complete program

fn main() {
  let marks = [70, 80];
  assert!(marks.iter().all(|score| (0..=100).contains(score)));
  match marks.get(2) {
    Some(score) => println!("Mark: {score}"),
    None => println!("No mark at this position"),
  }
}

Expected output

No mark at this position

Follow the execution

The two marks satisfy the asserted range. Index two is outside this two-element collection, so get reports None and the match prints a useful message. It avoids direct indexing that would panic.

Try the complete program in the Rust compiler. For tests, Cargo commands and local files, use the specified local environment.

Try a small variation

Your task: Would changing get(2) to marks[2] preserve this recovery behavior?

Rust 2024 · complete program

fn main() {
  let marks = [70, 80];
  assert!(marks.iter().all(|score| (0..=100).contains(score)));
  match marks.get(2) {
    Some(score) => println!("Mark: {score}"),
    None => println!("No mark at this position"),
  }
}

Worked answer

No. Direct out-of-bounds indexing panics, while get supplies None for the program to handle. Choose the operation that matches whether absence is expected.

Mistakes and limits to recognize

Panic may unwind or abort depending on configuration. Catching a panic is not a general replacement for Result, and not every failure can be caught. An assertion in this example checks prepared data; arbitrary external marks should be validated before use.

Check your understanding

Would changing get(2) to marks[2] preserve this recovery behavior?
Choose one answer. You can try again.

Answer and explanation

No.

No. Direct out-of-bounds indexing panics, while get supplies None for the program to handle. Choose the operation that matches whether absence is expected.

Take the idea into your next program

No. Direct out-of-bounds indexing panics, while get supplies None for the program to handle. Choose the operation that matches whether absence is expected. Panic may unwind or abort depending on configuration.

Further reading: the official Rust Book on validation, panic and checked access.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Traits and derived behavior →