fn try_option_some() -> Option<u8> {
if let val = Some(1) {
Some(val)
} else {
None
}
}
It's an early exit if the expression before is None/Error fn try_option_some() -> Option<u8> {
if let val = Some(1) {
Some(val)
} else {
None
}
}
It's an early exit if the expression before is None/Error fn try_option_some() -> Option<u8> {
Some(1)
} fn f() -> Result<A, E>
fn g() -> Result<B, E>
Then you can write fn h() -> Result<(A,B), E> {
let x = f()?;
let y = g()?;
Ok((x, y))
}
rather than having to do something like fn h() -> Result<(A,B), E> {
match f() {
Ok(x) => {
match g() {
Ok(y) => Ok((x,y)),
Err(e) => Err(e)
}
},
Err(e) => Err(e),
}
}
(written from memory, please excuse syntax errors)What's new is that this also works with Option<A> now.
Another sane alternative here is using and_then, map, etc.
Writing from memory too:
fn h() -> Result<(A, B), E> {
f().and_then(|x| g().map(|y| (x, y)))
}
..which seems to be a different style of control flow to choose from. On one hand, I suppose one may avoid using and_then with code dealing with side effects. On another hand, ? seems restricted to being used inside functions that have to return a a single type (like Result) they operate on.> functions that have to return a single type
Well, all functions have to return a single type, though that type may be a composite type, like a tuple.
Less pedantically, `?` lets you (well, will let you) unwrap values and convert their error cases between each other. So once the next round of stabilization happens, if you have a function that returns Results, you can mix ? on Options and Results in the body, and vice versa. And it can be extended for other types too. Basically, it's an early return "protocol" if you will.
do_this(x).ok_or(CustomError::ThisError)?;If you added extra code to manipulate things then that single if would still be enough, just place everything that happens after the extraction inside the success branch of the if statement.
You're missing a Some(val) at the end. Now you could remove the `if let val` as well to make it compile, but then that obfuscates what the ? operator was doing there.
I think it would have been much clearer to have 1 function which took a parameter of type Option<u8>, then did something with it after extracting with ?, then call it twice, once with Some(1), once with None. In addition I'd probably do something with val (e.g. add 1). And to prevent easy conversion to the if statement you could make the early return explicit by doing the extraction somewhere in a loop (so that you can't get at it with nested if statements).
I mean, this isn't hard to check, try compiling it.
I was saying it's misleading not only because it's wrong, but also because even if something is equivalent if you're trying to show how a feature works you want equivalent code that cleanly maps to the original; and isn't further reduced.
fn try_option_some(param: Option<u8>) -> Option<u8> {
if let Some(val) = param {
Some(val + 1)
} else {
None
}
}
fn main() {
print!("{:?}\n", try_option_some(None));
print!("{:?}\n", try_option_some(Some(2)));
}> if-else conditionals are expressions, and, all branches must return the same type.