The syntax for `if..let` feels unintuitive to me. How can I improve?

This code where we only care about a single variant of an enumeration (Option):

    let config_max = Some(3u8);
    match config_max {
        Some(max) => println!("The maximum is configured to be {max}"),
        _ => (),
    }

Can be rephrased as:

    let config_max = Some(3u8);
    if let Some(max) = config_max {
        println!("The maximum is configured to be {max}");
    }
  • For me this is somehow hard to remember because it seems like on the left-hand side of the assignment there is an expression Some(max); that is, it reminds me of, say let Some(max)=2; which seems wrong.

  • It also does not look like it evaluates to a bool, nor that it returns anything.

Maybe I should think of let (a,b,c)=... but idk, still have some doubts.

I do understand that the let is connected to max, but somehow still seems unintuitive to me.

I am not sure whether this is some thing am missing or weren't just gets used to this syntax.

==============

PS: I guess some of the issues are addressed by this Reddit comment Reddit - The heart of the internet, not all though.

// pattern binding a value to a variable
let a = ..;
let mut a = ..;

// matching a tuple
let (a, b, mut c) = (1, 2, 3);

// matching a struct
let MyStruct { foo, bar, .. } = MyStruct::new();

// matching a reference
let &a = &b;
let &mut a = &mut b;

// matching an array or slice
let [a, b, ..] = [1, 2, 3, 4];

Yes, the left side of a let binding is a pattern. But I'm not sure what else there is to say about it. It's useful, and you'll get used to it over time.

1 Like

But can you put Some in a standard assignment? And does let ever return something besides this case?

It is analogous to let. This is valid:

enum Container {
    Just(i32)
}
use Container::Just;
  
let config_max = Just(17);
let Just(max) = config_max;

This is also valid:

let config_max = Some(3u8);
let Some(max) = config_max else { panic!() };
1 Like

I see, I didn't know you could wrap it that way and when I tried it with Some it failed. Maybe I did something wrong.

Maybe you find the Reference a useful resource?

A let statement introduces a new set of variables, given by a pattern. The pattern is followed optionally by a type annotation and then either ends, or is followed by an initializer expression plus an optional else block.

let Some(max) = config_max;

is invalid because this doesn't say what should happen when config_max is None.

The pattern on the left of a let binding must match the right side. So you'll get a compiler error if you tried let Some(x) = 3.

When you use a simple variable name, let x = 3, the variable name is also a pattern. But variable names as patterns always match any expression. So the simple case works as expected, even though conceptually a pattern is always matched.

Yeah I should have, I think the last couple of interactions with the reference we're not very good (either too complex or missing some information) but this one is quite simple, thanks.