How to get any ControlFlow value? - rust

Using ControlFlow in try_fold seems better than Option in this case where one need to use any value.
But it's not very pleasant to use ControlFlow in try_fold because this irrefutable pattern shown below:
let (Break(value) | Continue(value)) =
values
.iter()
.try_fold(0, |previous, &current| match (previous) {
0 => Continue(1),
1 => Continue(2),
_ => Break(3),
});
Is there a way to get rid of this irrefutable pattern while using ControlFlow and retrieving the value?

Related

Using unwrap_or_else for error handling in Rust

I have a rust program that has a function
‘is_input_sanitized’ that takes an input
String m, and checks if the input is free of special characters.The method is being used on a separate function in the following way.
let a = match is_input_sanitized(m) {
Ok(m) => m,
Err(_) => { return Err("error"); },
};
I am trying to convert this snippet into using ‘unwrap_or_else’ which will return an error when the input is not sanitized.I have read the documentation and have not been able to decipher a proper way to achieve this. Is this conversion possible?
unwrap_or_else is for extracting Result values. It sounds to me like you don't want to extract the result, so much as make a new one and propagate errors. You have two different things you want to do here. The first is that you want to change the error from whatever it started as (indicating by your _ in the pattern match) to something you control, and the second is that you want to return errors.
Replacing the error can be done with map_err, which takes a function (such as a closure) and applies that function to the error if the Result is an Err. If the result is Ok, then it returns the current Result unmodified.
The second problem, returning on Err, is exactly what the question mark operator was invented for.
Chaining results using match can get pretty untidy; luckily, the ? operator can be used to make things pretty again. ? is used at the end of an expression returning a Result, and is equivalent to a match expression, where the Err(err) branch expands to an early return Err(From::from(err)), and the Ok(ok) branch expands to an ok expression.
So what you're looking for is
let a = is_input_sanitized(m).map_err(|_| "error")?;

Rust: What does the `#` (at sign) operator do?

I saw the following line in my code, and I am not sure what it does as I haven't encountered the # operator before.
if let e#Err(_) = changed {
...
}
Can this line be written without the # operator, what would that look like?
It's a way to bind the matched value of a pattern to a variable(using the syntax: variable # subpattern). For example,
let x = 2;
match x {
e # 1 ..= 5 => println!("got a range element {}", e),
_ => println!("anything"),
}
According to https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#-bindings and https://doc.rust-lang.org/reference/patterns.html#identifier-patterns, it is used for simultaneously matching to the pattern to the right of the # while also binding the value to the identifier to the left of the #.
To answer your second question, Yes, it would look like
if let Err(_) = &changed {
// continue to use `changed` like you would use `e`
}
Note that in order to continue to use changed inside the body, you need to match for the reference &changed. Otherwise it will be moved and discarded (unless it happens to be Copy).

Is there a shorthand for evaluating whether a refutable pattern matches?

As far as I can tell, refutable patterns can only be tested in match, if let, and while let expressions. To illustrate what I would like to do, consider the use of the => syntax from the match statement in the following context:
let val = get_optional_value();
if val => Some(inner) {
do_something(inner);
}
I could use an if let statement, but a more useful context would be in short closures:
get_optional_value()
.filter(|iv| iv => InnerVariant::VariantA)
.and_then(/* ... */)
As far as I can tell, the only solution to achieving this using pattern matching would be:
get_optional_value()
.filter(|iv| {
if let InnerVariant::VariantA = iv {
true
} else {
false
}
})
.and_then(/* ... */)
There is a similar question that did not get answered but the comments do point to the use of the ? operator that solves a related corner case for std::result::Result.
Rust 1.42 added the matches! macro. matches!(X, Y) returns a boolean indicating whether expression X matches the pattern Y.
In your case, it could be used like this:
get_optional_value()
.filter(|iv| matches!(iv, InnerVariant::VariantA))
.and_then(/* ... */)
This does not let you bind new names, you can only access the "inner" data in an optional if guard.

Can I avoid `_` in pattern matching with gen_range?

If I want to match the result of a rand::thread_rng().get_range(1, 3), I need to add a _ value even if I know there is only two possible values:
match rand::thread_rng().gen_range(1, 3) {
1 => println!("1"),
2 => println!("2"),
_ => panic!("never happens")
};
The _ case is useless but required.
I understand the compiler can't guess that gen_range(1, 3) can only return 1 or 2 but is there a way to avoid adding this useless line _ => panic!("never happens") with pattern matching (maybe with some hint to the compiler)? Or do I need to replace the last value (2) by _?
I understand the compiler can't guess that gen_range(1, 3) can only return 1 or 2
That is correct. gen_range returns an i32 in this case, and an i32 may have many more values.
is there a way to avoid adding this useless line _ => panic!("never happens")
As was covered in the comments, unreachable! better expresses your intent than just a plain panic!:
match rand::thread_rng().gen_range(1, 3) {
1 => println!("1"),
2 => println!("2"),
_ => unreachable!(),
};
replace the last value (2) by _?
This would be fine, but the "failure" case when you eventually change the arguments is likely harder to catch:
match rand::thread_rng().gen_range(1, 100) {
1 => println!("1"),
_ => println!("2"), // oops!
};
A version that panics is more likely to blow up obviously during testing. Which you choose is up to you and your risk tolerance.
The only "bullet proof" alternative is to use an enum { One, Two }, but it leads to more boilerplate and just forces the range check to be done slightly sooner
This works, and would be useful if you wanted to have the equivalent of the match multiple times in your code. This consolidates the logic to one location.
I'm a little surprised there isn't a macros 1.1 crate that allows something like #[derive(Rand)] for an enum... but there are some crates that seem to make it easier.
In this specific case, you could also generate a random boolean and just pick 1 or 2:
if rand::thread_rng().gen() {
println!("1")
} else {
println!("2")
}

How using Rust do I assign the value being matched as the result?

I've used "match" a little in Rust, and I've searched for a solution to this problem, because I'm sure there must be a solution. In the following example, in the case where the random number generated is not zero, I want the random-number generated to be assigned to the variable i_bal. In other words, instead of assigning "23456" as per my example, I want to assign the actual random number being tested in the match. I know that there may be better ways of solving this, however, I'd like to know the solution using this method.
Example :
let i_bal: i64 = match std::rand::task_rng().gen() {
0 => 1234,
_ => 23456
};
Instead of the wildcard pattern you can use the variable pattern. They both match everything, but with the variable pattern the matched value is bound to the name:
let i_bal: i64 = match std::rand::task_rng().gen() {
0 => 1234,
x => x
};
Why in some cases you'd want to use the wildcard pattern is so that you make it clear you don't need the value, and so that you don't have to pollute the scope with unnecessary variable names
For example if you had a tuple of (high, low, open, close), and only wanted the variables high and low from it you could do:
let (high, low, _, _) = tickerData

Resources