How to handle error in unwrap() function? [closed] - rust

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
What is the best way to handle the error when reading arguments from the CLI?
For example, when the second argument is not provided in the following code?
use std::env;
fn main() {
let filename = env::args().nth(0).unwrap();
let other_argument = env::args().nth(1).unwrap();
}

I would recommend to use the match to differentiate between the value of enums.
An example which illustrates this approach for Options like you might need it for your arguments (you could also use different approaches) and Result
use std::env;
use std::fs;
fn main() {
// match 1
// handle Options https://doc.rust-lang.org/std/option/enum.Option.html using match
match env::args().nth(1) {
Some(v) => {
println!("arg 1: {:?}", v);
// match 2
// handle Result https://doc.rust-lang.org/std/result/ using match
match fs::read_to_string(&v) {
Ok(contents) => println!("{}", contents),
Err(e) => println!("{}", e),
};
}
None => {
println!("you have not passed an argument.");
}
}
}
Like already others wrote, I can also really recommend the crate https://docs.rs/structopt/latest/structopt/ in order to evaluate command line arguments.

I imagine that if the user does not input those arguments then you probably want the program to crash.
You can use expect which is a nice alternative to unwrap because it lets you specify the error message when crashing.
let filename = env::args().nth(0).expect("Did not provide the filename argument");
https://learning-rust.github.io/docs/e4.unwrap_and_expect.html
If you want the "best" way to deal with this, I recomment using the structopt library for handling program arguments.
https://lib.rs/crates/structopt
Fyi: not sure if this is your intended behavior but the 0th argument is actually the name of the program being executed rather than the first argument on the command line.

Related

Error handling for applications: how to return a public message error instead of all the chain of errors and tracing it at the same time?

PROLOGUE
I'm using async-graphql and I have hundreds of resolvers and for each resolver I would like to trace all the possible errors.
In each method of my app I'm using anyhow::{Error}.
Right now I have code similar to this for each resolver:
#[Object]
impl MutationRoot {
async fn player_create(&self, ctx: &Context<'_>, input: PlayerInput) -> Result<Player> {
let services = ctx.data_unchecked::<Services>();
let player = services
.player_create(input)
.await?;
Ok(player)
}
}
So I thought about using the below code (note the added line with .map_err()):
#[Object]
impl MutationRoot {
async fn player_create(&self, ctx: &Context<'_>, input: PlayerInput) -> Result<Player> {
let services = ctx.data_unchecked::<Services>();
let player = services
.player_create(input)
.await
.map_err(errorify)?;
Ok(player)
}
}
fn errorify(err: anyhow::Error) -> async_graphql::Error {
tracing::error!("{:?}", err);
err.into()
}
Now the error is traced along with all the error chain:
ERROR example::main:10: I'm the error number 4
Caused by:
0: I'm the error number 3
1: I'm the error number 2
2: I'm the error number 1
in example::async_graphql
QUESTION 1
Is there a way to avoid the .map_err() on each resolver?
I would like to use the ? alone.
Should I use a custom error?
Can we have a global "hook"/callback/fn to call on each error?
QUESTION 2
As you can see above the chain of the error is the inverse.
In my graphql response I'm getting as message the "I'm the error number 4" but I need to get the "I'm the error number 2" instead.
The error chain is created using anyhow like this:
main.rs: returns error with .with_context(|| "I'm the error number 4")?
call fn player_create() in graphql.rs: returns with .with_context(|| "I'm the error number 3")?
call fn new_player() in domain.rs: returns with .with_context(|| "I'm the error number 2")?
call fn save_player() in database.rs: returns with .with_context(|| "I'm the error number 1")?
How can I accomplish this?
I'm really new to Rust. I come from Golang where I was using a struct like:
type Error struct {
error error
public_message string
}
chaining it easily with:
return fmt.Errorf("this function is called but the error was: %w", previousError)
How to do it in Rust?
Do I necessarily have to use anyhow?
Can you point me to a good handling error tutorial/book for applications?
Thank you very much.
I would suggest you define your own error for your library and handle them properly by using thiserror crate.
It's like Go defining var ErrNotFound = errors.New(...) and use fmt.Errorf(..., err) to add context.
With the powerful tool enum in Rust, so you can handle every error properly by match arms. It also provides really convenient derive macro like #[from] or #[error(transparent)] to make error conversion/forwarding easy.
Edit 1:
If you want to separate public message and tracing log, you may consider defining you custom error struct like this:
#[derive(Error, Debug)]
pub struct MyError {
msg: String,
#[source] // optional if field name is `source`
source: anyhow::Error,
}
and implement Display trait for formatting its inner msg field.
Finally, you could use macro in tracing-attributes crate:
#[instrument(err(Debug))]
fn my_function(arg: usize) -> Result<(), std::io::Error> {
Ok(())
}
Is there a way to avoid the .map_err() on each resolver?
Yes, you should be able to remove it unless you really need to convert to async_graphql::Error.
Do I necessarily have to use anyhow?
No, but it makes this easier when using ? on different error types.
I'm really new to Rust. I come from Golang where I was using a struct like:
Take a look at thiserror which lets you build you own enum of error variants.

What's the functional approach to replace this match block?

What's the functional approach to replace the below match?
match second_db.player_create(player_id).await {
Ok(o) => Ok(o),
Err(err) => {
first_db.player_delete(player_id).await?;
Err(err)
}
}
As others have pointed out, the usual helper methods on Result and Option do not work with async (see links below). However, these methods are mostly about transforming the Result / Option which you are not doing. Hence, your code could be rephrased to the following (assuming you want to return the result of the match expression):
let result = second_db.player_create(player_id).await;
if result.is_err() {
first_db.player_delete(player_id).await?;
}
result
This omits the "mapping" part of both branches and is, in my opinion, easier to understand.
Related discussions:
How to use async/await inside closure of `Option::and_then` or `Option::map` without using OptionFuture?
https://users.rust-lang.org/t/how-to-run-async-code-within-option-result-function-chain/64053

Replacing Unwrap()s with ? - compiler complaining on functions that do return Result or Option [duplicate]

This question already has answers here:
What is this question mark operator about?
(4 answers)
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
(4 answers)
the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
(1 answer)
What is the idiomatic way to handle/unwrap nested Result types?
(2 answers)
Closed 7 months ago.
The community reviewed whether to reopen this question 7 months ago and left it closed:
Original close reason(s) were not resolved
I'm only a few days into my Rust journey and going over my now functionally completed first project, working on exercising unwrap()s from my code.
The first two instances I've tried, I've completely failed and I cannot work out why. I have this line in my code:
let json = str::from_utf8(&buf).unwrap();
from_utf8 returns Result<&str, Utf8Error>, but trying:
let json = str::from_utf8(&buf)?;
Has a compiler error of "This function should return Result or Option to accept ?", but it does return Result. I can only assume that the pointer & is having an effect here?
I've refactored this now to:
match str::from_utf8(&buf) {
Ok(json) => {
let msg: MyMessage = serde_json::from_str(json).unwrap();
self.tx.try_send((msg, src)).expect("Could not send data");
}
Err(e) => {}
};
I still need to work out what to do in the Err but I've gotten rid of the unwrap() call. However, there's another.
serde_json::from_str(json).unwrap();
This returns Result<T>, so:
serde_json::from_str(json)?;
This is also complaining about the fact it should return Result when it already does.
At this point, it's safe to assuming I'm really confused and I don't understand half as much as a thought I did.
Countless blogs just say use ?, yet, in every instances I think it should work and the return types appear suitable, the compiler says no.
Would the From trait work here? Is it common to have to write traits like this?
from_utf8 returns Result<&str, Utf8Error>, but trying:
let json = str::from_utf8(&buf)?;
Has a compiler error of This function should return Result or Option to accept ?. But it does return Result.
This function here refers to the outer function. That is, the function you are writing, not from_utf8.
? will return an error from your function if there was one, thus your function needs the right return type to be able to return an error.
Because from_utf8 is not the source of the issue, you'd get the same error like this too:
let r = Err(...);
let json = r?;
The ? operator is roughly equivalent to a match with an early return for the error case, so in your example
fn foo() {
let json = str::from_utf8(&buf)?;
// ...
}
is roughly equivalent to
fn foo() {
let json = match str::from_utf8(&buf) {
Ok(j) => j,
Err(e) => return Err(e.into()),
}
// ...
}
This should make it clear where the error is coming from. You are trying to return a Result from a function that doesn't return anything.

Moving context into several closures?

I have found a way to move context into several closures, but it looks ugly. I do it with help of Rc and cloning each variable I need to use for each closure. Particularly I don't like to clone every variable for every closure I want to use:
let mut context = Rc::new( Context { a : 13 } );
..
let context_clone_1 = Rc::clone( &context );
engine.on_event1( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
let context_clone_2 = Rc::clone( &context );
engine.on_event2( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
It is an extensive way to go and I feel there must be a better way to do it. Also, uncommenting line // context_clone_1.a += 1; breaks the compilation. What is the proper way of solving problems like this in Rust?
Here is a playground with minimal code.
There are two "problems" here:
Since you specifically asked about context_clone_1.a += 1;: When putting a value into an Rc, there could be multiple references to that value, derived from the independent Rc owners. If mutation was allowed, this would also allow simultaneous mutation and aliasing, which is not allowed in Rust; therefore Rc does not allow mutating its inner value. A common approach to regain mutability is to put the value into a RefCell, which provides mutability through try_borrow_mut() with a runtime check that ensures no aliasing occurs. A Rc<RefCell<T>> is commonly seen in Rust.
Regarding the use of Rc: The way your code is currently set up is actually fine, at least if that's how it should work. The way the code is currently structured allows for flexibility, including cases where multiple Context-objects provide callback implementations on different events. For example, this is currently possible:
let context1 = Context { a : 13 };
engine.on_event1(Box::new(move ||
{
println!("on_event1 : {}", context1.a );
});
let context2 = Context { a : 999 };
engine.on_event2(Box::new(move ||
{
println!("on_event1 : {}", context2.a );
});
In case you have exactly one Context (as in your example), and since the Engine needs to make sure that all callbacks are alive while it itself is alive, you'll need to put each callback - which is structured as a completely separate thing - into a Rc. In your case, all Rc end up pointing to the same object; but they don't have to and this is what your code currently allows for.
A more simple solution would be to define a trait for Context, something along the lines of
trait EventDriver {
fn event1(&mut self, &Engine);
fn event2(&mut self, &Engine);
}
... and then have Context implement the trait. The Engine-struct then becomes generic over E: EventDriver and Context becomes the E in that. This solution only allows for exactly one instance of Context to provide event callbacks. But since Engine is the owner of that object, it can be sure that all callbacks are alive while it itself is alive and the whole Rc-thing goes away.

How do I modify specific component when a key is pressed in Bevy? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Consider a simple component representing the player struct TilePos(i32, i32); and spawned as commands.spawn((TilePos(0, 0), ));.
What's the correct way of reacting to keyboard input, e.g. the arrow keys, and change TilePos by one whenever a key is pressed once?
You probably want to look at the cookbook for more examples.
If there is only one player, then you should make it a resource so that you can just do: ResMut<TilePos> in the function definition.
Otherwise you can do:
#[derive(Default)]
struct State {
event_reader: EventReader<KeyboardInput>,
}
/// This system prints out all keyboard events as they come in
fn print_keyboard_event_system(
mut state: Local<State>,
keyboard_input_events: Res<Events<KeyboardInput>>,
mut query: Query<&mut TilePos>
) {
for event in state.event_reader.iter(&keyboard_input_events) {
if event.state == bevy::input::ElementState::Pressed && event.key_code == Some(bevy::input::keyboard::KeyCode::Up){
for mut t in &mut query.iter_mut() {
t.1 += 1;
println!("New Tile: {} {}", t.0, t.1);
println!("{:?}", event);
}
}
}
}
If you were wanting to edit a specific tile, then you could spawn it with another component (.with()) and make the query more specific with Query<TilePos, With<Specific>>.
This code is adapted from here.

Resources