rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

let-else extension

Open tnthung opened this issue 6 months ago • 7 comments

Currently we can use

fn foo(v: Option<u32>) {
  let Some(v) = v else { 
    // do sth then term the call
  };
}

to quickly extract the only pattern wanted.

For Option<T> this works perfectly. However, it's not working so well with Result<T>.

fn foo(v: Result<u32, String>) {
  let Ok(v) = v else { 
    // error value is lost
  };
}

I'm thinking it would be nice to implement following syntax.

fn foo(v: Result<u32, String>) {
  let Ok(v) = v else as e {
    // e has value of `Err(String)` allows you to do some
    // logic around the value.
  };
}

fn bar(v: Result<u32, String>) {
  // for binary enum, you can use pattern matching
  let Ok(v) = v else as Err(e) {
    // e has type of `String` allows you to do some
    // logic around the value.
  };
}

enum SomeValue {
  A,
  B(bool),
  C(u32),
}

fn foobar(v: SomeValue) {
  // for non-binary enum, you cannot do pattern matching
  let SomeValue::B(v) = v else as rest {
    // rest has can either be `SomeValue::A`
    // or `SomeValue::C(u32)`.
  };
}

fn barfoo(v: SomeValue) {
  // non-captured syntax is also available
  let SomeValue::B(v) = v else {
    // you lose the rest of branches
  };
}

This gives you a chance to process the else case. Currently we would need to do things as follows to get around this problem.

fn foo(v: Result<u32, String>) {
  let v = match v {
    Ok(v) => v,
    Err(err) => {
      // handle the error
    }
  };
}

This is working and it's explicit, which is good, don't get me wrong. But sometimes it's too explicit to verbose extent, IMO. When multiple were stacked, it's even more unreadable.

tnthung avatar Jun 13 '25 02:06 tnthung