title | timestamp | author | published | description | tags | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Indicating error, returning Result of Ok or Err in Rust |
2024-03-14 03:30:01 -0700 |
szabgab |
true |
They way a function can indicate success or failure is by returning a Result enum. |
|
Some function we implement might fail. Either because the caller did not supply the correct parameter or some other issue. How can we indicate failure? In some languages failure is indicated by the raising (throwing) of exceptions. In other languages the function can return some value (e.g. null, undef etc.) to indicate failure.
In Rust a function that might need to report an error should return a value of Result type. In general a Result
can have either a value wrapped in Ok()
or a value wrapped in Err()
. What kind of values are wrapped in either of those is up to the author of the function.
In the first example we have a function that expects an integer number between -100 and +100 and then checks if the number is smaller or bigger or exactly the same
as the hidden_number
. This might be part of a number guessing game where the hidden number was generated by a random generator. However now we would like to focus
on the error reporting part.
The guess
function return Result<&'static str, &'static str>
. The generic description of Result is Result<T, E>
so the first type is the type of the successful result
the second type is that of the error. In our case they are both static
strings that are baked in the binary at compilation time.
In case the user supplied a number that is out of range we return a static string wrapped in the Err()
call.
In case the number was in range we supply our message wrapped in an Ok()
call.
The caller will receive a value of Result
type and it has to be handled somehow. There are plenty of ways to handle it. For example calling unwrap
will panic!
if the result contained something
wrapped in Err
and will return the content of the Ok()
if the result contained a value wrapped in Ok()
. This is mostly used in tests.
The caller can also use match
to handle both the Ok()
and the Err()
case with additional code.
See the functions associated with Result enum to find more ways to handle the errors.
{% include file="examples/return-result-str/src/main.rs" %}
We might want to be more precise in our error message and even include the number we received. In this case we need to generate the error message
while the program is already running so we cannot return a static
string wrapped in Err()
. Therefore we change the second type in the returning Result
to be String
.
This has some impact on how we generate the error message using the format!
macro and how we use String::from
when we would like to verify the results.
{% include file="examples/return-result-string/src/main.rs" %}
There are many more types we can return as part of a Result
enum.
There are plenty more ways to handle the Result
by the caller.
It just occurred to me that including the valid range in the error message would be even more useful. I'll leave it as an exercise to the reader.