How do I access a variable outside of an `if let`

2020-04-27 07:22发布

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?

标签: rust
2条回答
趁早两清
2楼-- · 2020-04-27 07:40

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);
查看更多
何必那么认真
3楼-- · 2020-04-27 07:45

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);
}
查看更多
登录 后发表回答