Skip to main content
Brave Programmer Logo

BraveProgrammer

BraveProgrammer

HomeProjectsBlogsCoursesLessonsAbout

Site footer

BraveProgrammer

Free coding courses, practical tutorials, and real projects from BraveProgrammer. Learn web development with React, Next.js, and TypeScript.

Navigation

  • Home
  • Projects
  • Blogs
  • Courses

Resources

  • About
  • Lessons

© 2026 BraveProgrammer. All rights reserved.

  1. Courses
  2. /
  3. Rust Fundamentals

Lesson 20 of 50 · rust

Panic and Unwinding

Duration: 12 minutes

Panic and Unwinding\n\nA panic is an unrecoverable error that terminates the program (or thread). Rust provides the panic! macro and strategies for handling panics.\n\n## The Panic Macro\n\nrust\nfn main() {\n panic!(\"Something went very wrong!\");\n // This line never executes\n}\n\n\nOutput:\n\nthread 'main' panicked at 'Something went very wrong!', src/main.rs:2:5\n\n\n## Panic From Unwrapping\n\nCommon ways panics occur:\n\nrust\nfn main() {\n let x: Option<i32> = None;\n let val = x.unwrap(); // panics: called `Option::unwrap()` on a `None` value\n \n let v = vec![1, 2, 3];\n let item = v[10]; // panics: index out of bounds\n \n let nums = \"abc\";\n let result: i32 = nums.parse().unwrap(); // panics: invalid digit\n}\n\n\n## When to Panic\n\n### Good Uses\n- Unrecoverable errors: No sensible recovery available\n- Development: Assert assumptions in tests\n- Examples/Prototypes: Simplify code for clarity\n\n### Bad Uses\n- Expected failures: Should use Result instead\n- File not found: Use Result and handle gracefully\n- Invalid input: Validate and return error\n\n## Assertions\n\nAssert conditions hold, panic if they don't:\n\nrust\nfn divide(a: i32, b: i32) -> i32 {\n assert!(b != 0, \"Division by zero!\");\n a / b\n}\n\nfn main() {\n // In debug builds, checks are run\n // In release builds, checks are removed (unsafe!)\n let result = divide(10, 2);\n println!(\"Result: {}\", result);\n}\n\n\n## Debug vs Release Panics\n\n### Debug Mode\nrust\nlet v = vec![1, 2, 3];\nlet item = v[99]; // panics\n\n\n### Release Mode\nOut-of-bounds access is undefined behavior (Rust still checks in safe code though).\n\n## Catching Panics\n\nYou can catch panics using catch_unwind:\n\nrust\nuse std::panic;\n\nfn main() {\n let result = panic::catch_unwind(|| {\n panic!(\"Oops!\")\n });\n \n match result {\n Ok(_) => println!(\"No panic\"),\n Err(_) => println!(\"Caught a panic!\"),\n }\n}\n\n\n## Panic Hooks\n\nCustomize panics with hooks:\n\nrust\nuse std::panic;\n\nfn main() {\n panic::set_hook(Box::new(|info| {\n if let Some(s) = info.payload().downcast_ref::<&str>() {\n eprintln!(\"Custom panic handler: {}\", s);\n }\n }));\n \n panic!(\"Something failed\");\n}\n\n\n## Unwinding vs Aborting\n\nTwo strategies for handling panics:\n\ntoml\n# In Cargo.toml\n[profile.dev]\npanic = \"unwind\" # Default: unwind stack\n\n[profile.release]\npanic = \"abort\" # Faster: immediately exit\n\n\nUnwind** (default):\n- Cleans up resources via drop\n- Slower compilation\n- Allows catching panics\n\nAbort:\n- Immediately terminates\n- Faster code\n- No cleanup\n\n## Best Practices\n\n1. Use Result for possible failures: Not panics\n2. Assert preconditions: In development\n3. Document panic conditions: In documentation\n4. Test panic scenarios: Ensure behavior is expected\n5. Avoid unwrap in libraries: Use Result propagation\n\n## Practical Example\n\nrust\nfn process_number(s: &str) -> Result<i32, String> {\n // Use Result for recoverable errors\n s.parse::<i32>()\n .map_err(|_| String::from(\"Not a valid number\"))\n}\n\nfn main() {\n // Handle Result properly\n match process_number(\"42\") {\n Ok(n) => println!(\"Got: {}\", n),\n Err(e) => println!(\"Error: {}\", e),\n }\n \n // Only use unwrap in examples\n let num = process_number(\"99\").unwrap(); // OK for examples\n}\n

Previous: Error Handling with ResultNext: Traits