DEV Community

Cover image for What Are the Ways to Handle Errors in Rust?
Mansoor Ahmed
Mansoor Ahmed

Posted on

What Are the Ways to Handle Errors in Rust?

A logic error in programming can be a bug during a program that causes it to work incorrectly but to not terminate abnormally (or crash). … a program unlike with a software error, a program with a logic error may be a valid program within the language, though it doesn’t behave as intended. The error overcoming from bad code in some programs is involved in producing the erroneous result.
There are basically three sorts of errors that you simply must deal with when writing programs:
Syntax errors — Syntax errors represent grammar errors within the use of the programing language
Runtime errors — Runtime errors occur when a program with no syntax errors asks the pc to try to do something that the pc is unable to reliably do.
Logic errors — Logic errors occur when there’s a design flaw in your program.
In Rust — Compiler does the foremost significant job to stop errors in Rust programs. It analyzes the code at compile-time and issues warnings if the code doesn’t follow memory management rules or lifetime annotations correctly.
The Rust compiler analyzes not only issues associated with lifetimes or memory management and also common coding mistakes.
Rust’s commitment to reliability extends to error handling. Errors are a fact of life in software, so Rust features a number of features for handling situations during which something goes wrong. Rust requires in many cases to acknowledge the likelihood of a mistake and take some action before code will compile. This need makes our program more robust by ensuring that we’ll discover errors and handle them appropriately before you’ve deployed your code to production!
Error messages are very descriptive and that we can easily see where is that the error. But while we will not identify the difficulty via the error message, rustc –explain commands help us to spot the error type and the way to unravel it, by showing simple code samples that express an equivalent problem and therefore the solution we’ve to use.
Most languages don’t distinguish between these two sorts of errors and handle both in the same way, using mechanisms like exceptions. Rust doesn’t have exceptions. Instead, it’s the sort Result for recoverable errors and panic! a macro that stops execution when the program encounters an unrecoverable error. This chapter covers calling panic! first then talks about returning Result values. Additionally, we’ll explore considerations when deciding whether to undertake to get over a mistake or to prevent the execution.
In some cases, while a mistake happens we will not do anything to handle it if the error is some things, which shouldn’t have happened. In other words, if it’s an unrecoverable error.
Also once we aren’t employing a feature-rich debugger or proper logs, sometimes we’d like to debug the code by quitting the program from a selected line of code by printing out a selected message or worth of a variable binding to know the present flow of the program.
For the above cases, we will use panic! macro.
Rust has the panic! macro. When the panic! the macro executes, our program will print a failure message, unwind and pack up the stack, then quit. This most ordinarily occurs when a bug of some kind has been detected and it’s not clear to the programmer the way to handle the error.
Quit From a selected Line.
fn main() {
// some code
// if we'd like to debug in here
// — — — — — Compile-time error — — — — –
Thread ‘main’ panicked at ‘explicit panic’, src/
The call to panic! causes the error message contained within the last two lines. the primary line shows our panic message and therefore the place in our ASCII text file where the panic occurred: src/ indicates that it’s the second line, the fifth character of our src/ file.
In this case, the road indicated is a component of our code, and if we attend that line, we see the panic! macro call. In other cases, the panic! the call could be in code that our code calls, and therefore the filename and line number reported by the error message is going to be someone else’s code where the panic! macro is named, not the road of our code that eventually led to the panic! call. we will use the backtrace of the functions the panic! the call came from to work out the part of our code that’s causing the matter. We’ll discuss what a backtrace is in additional detail next.

  1. Quit With A Custom Error Message. #[allow(unused_mut)] //A lint attribute wont to suppress the warning; username variable doesn't get to be mutable fn main() { let mut username = String::new(); // some code to urge the name if username.is_empty() { panic!("Username is empty!"); } println!("{}", username); } // — — — — — Compile-time error — — — — – Thread ‘main’ panicked at ‘Username is empty!’, src/ USING A PANIC! BACKTRACE : Let’s check out another example to ascertain what it’s like when a panic! the decision comes from a library due to a bug in our code rather than from our code calling the macro directly. Listing 9-1 has some code that attempts to access a component by index during a vector. fn main() { let v = vec![1, 2, 3]; v[99]; } Here, we’re attempting to access the 100th element of our vector (which is at index 99 because indexing starts at zero), but it's only 3 elements. during this situation, Rust will panic. Using [ ] is meant to return a component, but if you pass an invalid index, there’s no element that Rust could return here that might be correct. BACKTRACE : To protect your program from this type of vulnerability, if you are trying to read a component at an index that doesn’t exist, Rust will stop execution and refuse to continue. Let’s see it by trying: $ cargo run Compiling panic v0.1.0 (file:///projects/panic) Finished dev [unoptimized + debuginfo] target(s) in 0.27s Running target/debug/panic thread ‘main’ panicked at ‘index out of bounds: the len is 3 but the index is 99’, libcore/slice/ Note: Run with RUST_BACKTRACE=1 for a backtrace. This error indicates at a file we didn’t write, libcore/slice/ That’s the implementation of slice within the Rust ASCII text file. The code that gets run once we use [] on our vector v is in libcore/slice/, which is where the panic! is really happening. The next note line tells us that we will set the RUST_BACKTRACE environment variable to urge a backtrace of exactly what happened to cause the error. A backtrace may be a list of all the functions that are called to urge to the present point. Backtraces in Rust work as they are doing in other languages: the key to reading the backtrace is to start out from the highest and skim until you see files you wrote. That’s the spot where the matter originated. The lines above the lines mentioning our files are code that our code is called; the lines below are code that is called our code. These lines may include core Rust code, standard library code, or crates that you’re using. Let’s try getting a backtrace by setting the RUST_BACKTRACE environment variable to any value except 0. Listing 9–2 shows output almost like what you’ll see. RECOVERABLE ERRORS WITH RESULTS : Most errors aren’t serious enough to need the program to prevent them entirely. Sometimes, when a function fails, it’s for a reason that you simply can easily interpret and answer. for instance, if you are trying to open a file in which the operation fails because the file doesn’t exist, you would possibly want to make the file rather than terminating the method. Recall from “Handling Potential Failure with the Result Type”, that the Result enum is defined as having two variants, Ok and Err, as follows: #![allow(unused_variables)] fn main() { enum Result { Ok(T), Err(E), } } The T and E are generic type parameters: we’ll discuss generics in additional detail within the Chapter ( generic data types ). What you would like to understand immediately is that T represents the sort of worth that will be returned during a success case within the Ok variant, and E represents the sort of error that will be returned during a failure case within the Err variant. Because Result has these generic type parameters, we will use the Result type and therefore the functions that the quality library has defined in it in many various situations where the successful value and error value we would like to return may differ. How can we know File::open returns a Result? Let’s try it! we all know that the return sort of File::open isn’t of type u32, so let’s change the let f statement to this: let f: u32 = File::open(“hello.txt”); This tells us the return sort of the File::open function may be a Result. The generic parameter T has been filled in here with the sort of the success value, std::fs::File, which may be a file handle. the sort of E utilized in the error value is std::io::Error. This return type means the decision to File::open might succeed and return a filehandle that we will read from or write to. The call also might fail: for instance, the file won’t exist, or we’d not have permission to access the file. The File::open function must have how to inform us whether it succeeded or failed and at an equivalent time give us either the filehandle or error information. This information is strictly what the Result enum conveys. Using a match expression to handle the Result variants which may be returned use std::fs::File; fn main() { let f = File::open("hello.txt"); let f = match f { Ok(file) => file, Err(error) => { panic!("There was a drag opening the file: {:?}", error) }, }; } Note that, just like the Option enum, the Result enum and its variants are brought into scope by the prelude, so we don’t get to specify Result:: before the Ok and Err variants within the match arms. Here we tell Rust that when the result’s Ok, return the inner file value out of the Ok variant and that we then assign that filehandle value to the variable f. After the match, we will use the filehandle for reading or writing. The output from the panic! macro: Thread ‘main’ panicked at ‘There was a drag opening the file: Error { repr: Os { code: 2, message: “No such file or directory” } }’, src/ For more details visit:

Discussion (0)