Reputation: 4409
I'm trying to access command line arguments. If the argument exists, do something, if not, do nothing. I have this code:
fn main() {
if let Some(a) = std::env::args().nth(2) {
let b = a;
}
println!("{}", a);
}
I am not able to access a
or b
outside of this scope:
error[E0425]: cannot find value `a` in this scope
--> src/main.rs:6:20
|
6 | println!("{}", a);
| ^ not found in this scope
How do I resolve this? Is there a better way to approach what I'm trying to do?
Upvotes: 5
Views: 7777
Reputation: 604
I agree that you should either do whatever you want to do inside the if-else block
s. If you just to not indent your code and your else
block is small, you can inverse your if-condition
.
Instead of
let arg = std::env::args().nth(2);
if let Some(a) = arg {
let b = a;
// do stuff
} else {
// do other stuff
}
you can do this
let arg = std::env::args().nth(2);
if arg.is_none() {
// do other stuff
}
let b = arg.unwrap();
// do stuff
If you want the variable to be available in the outer scope, but assign it a value in an inner scope, you can declare it outside.
let arg = std::env::args().nth(2);
let a; // declared but not assigned
if let Some(b) = arg {
a = b; // wasn't mut but first assignment can be done here
} else {
a = "Foobar".to_string();
}
println!("{}", a); // available here but was assigned the value inside if
Upvotes: 2
Reputation: 31173
For an understanding of what's going on, have a look at the answer by Shepmaster
I'm not sure what you expect to happen in case the condition is not met. If you just want to abort the program in that case, the idiomatic Rust way is to use unwrap
or expect
.
// panics if there are fewer than 3 arguments.
let a = env::args().nth(2).unwrap();
println!("{}", a);
If you want a default value in case the argument does not exist, you can use unwrap_or
.
// assigns "I like Rust" to a if there are fewer than 3 arguments
let a = env::args().nth(2).unwrap_or("I like Rust".to_string());
println!("{}", a);
As a further alternative, you can use the feature that in Rust almost everything is an expression:
let b = if let Some(a) = env::args().nth(2) {
a
} else {
// compute alternative value
let val = "some value".to_string();
// do operations on val
val
};
println!("{}", b);
The idiomatic Rust way to write that would be with closures and unwrap_or_else
:
let b = env::args().nth(2).unwrap_or_else(|| {
// compute alternative value
let val = "some value".to_string();
// do operations on val
val
});
println!("{}", b);
Upvotes: 12
Reputation: 430614
In Rust, it's always useful to ask yourself "what is the type of this variable?". Let's run with your example and pretend it works:
let arg = Some(true);
if let Some(a) = arg {
let b = a;
}
println!("{:?}", b);
What is the type of b
at the println
line? Maybe you'd like it to be a boolean, but what is the type if the if
clause doesn't pass? There isn't one! In other languages, maybe that would be nil
or null
, but Rust encodes that information with the Option
type - that's where Some
and None
come from!
Additionally, scopes are very meaningful in Rust. Items defined inside a scope don't leak outside that scope:
{
let a = 4;
}
println!("{}", a); // NOPE!
Between the two of these pieces, the code you want to write isn't possible. I agree that the right solution is to embed the println inside the if:
let arg = Some(true);
if let Some(a) = arg {
println!("{:?}", a);
}
Upvotes: 7