Referring to matched value in Rust - rust

Suppose I have this code:
fn non_zero_rand() -> i32 {
let x = rand();
match x {
0 => 1,
_ => x,
}
}
Is there a concise way to put the rand() in the match, and then bind it to a value. E.g. something like this:
fn non_zero_rand() -> i32 {
match let x = rand() {
0 => 1,
_ => x,
}
}
Or maybe:
fn non_zero_rand() -> i32 {
match rand() {
0 => 1,
_x => _x,
}
}

A match arm that consists of just an identifier will match any value, declare a variable named as the identifier, and move the value to the variable. For example:
match rand() {
0 => 1,
x => x * 2,
}
A more general way to create a variable and match it is using the # pattern:
match rand() {
0 => 1,
x # _ => x * 2,
}
In this case it is not necessary, but it can come useful when dealing with conditional matches such as ranges:
match code {
None => Empty,
Some(ascii # 0..=127) => Ascii(ascii as u8),
Some(latin1 # 160..=255) => Latin1(latin1 as u8),
_ => Invalid
}

You can bind the pattern to a name:
fn non_zero_rand() -> i32 {
match rand() {
0 => 1, // 0 is a refutable pattern so it only matches when it fits.
x => x, // the pattern is x here,
// which is non refutable, so it matches on everything
// which wasn't matched already before
}
}

Related

How to convert 2 bounded loop to iteration syntax

How can I convert this loop based implementation to iteration syntax?
fn parse_number<B: AsRef<str>>(input: B) -> Option<u32> {
let mut started = false;
let mut b = String::with_capacity(50);
let radix = 16;
for c in input.as_ref().chars() {
match (started, c.is_digit(radix)) {
(false, false) => {},
(false, true) => {
started = true;
b.push(c);
},
(true, false) => {
break;
}
(true, true) => {
b.push(c);
},
}
}
if b.len() == 0 {
None
} else {
match u32::from_str_radix(b.as_str(), radix) {
Ok(v) => Some(v),
Err(_) => None,
}
}
}
The main problem that I found is that you need to terminate the iterator early and be able to ignore characters until the first numeric char is found.
.map_while() fails because it has no state.
.reduce() and .fold() would iterate over the entire str regardless if the number has already ended.
It looks like you want to find the first sequence of digits while ignoring any non-digits before that. You can use a combination of .skip_while and .take_while:
fn parse_number<B: AsRef<str>>(input: B) -> Option<u32> {
let input = input.as_ref();
let radix = 10;
let digits: String = input.chars()
.skip_while(|c| !c.is_digit(radix))
.take_while(|c| c.is_digit(radix))
.collect();
u32::from_str_radix(&digits, radix).ok()
}
fn main() {
dbg!(parse_number("I have 52 apples"));
}
[src/main.rs:14] parse_number("I have 52 apples") = Some(
52,
)

Strange matching behaviour in for loop

Rust noob here. I am puzzled as to why I get this strange behaviour when matching the variable over which I am iterating through a range, with the max of that range. Instead of only matching with the last item, it matches everything! Can someone please explain the output and compiler warning I get from this code:
fn main() {
let maxi = 2;
for i in 0..=maxi {
match i {
maxi => {
println!("i={} matched maxi={}",i,maxi);
}
_ => {
println!("i={} matched with _",i);
}
}
}
}
The compiler output is as follows
warning: unreachable pattern
--> se_match_loop.rs:7:15
|
5 | maxi => {
| ---- matches any value
6 | println!("i={} matched maxi={}",i,maxi);
7 | } _ => {
| ^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: 1 warning emitted
When I execute the compiled script, this is the output
i=0 matched maxi=0
i=1 matched maxi=1
i=2 matched maxi=2
But if I declare maxi as a constant (with const instead of let), I get the expected output
i=0 matched _
i=1 matched _
i=2 matched maxi=2
This is documented under Matching Named Variables.
match starts a new scope, variables declared as part of a pattern
inside the match expression will shadow those with the same name
outside the match construct, as is the case with all variables.
For example, the following code
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {:?}", y),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {:?}", x, y);
}
will print
Matched, y = 5
at the end: x = Some(5), y = 10
So let's consider your first snippet,
fn main() {
let maxi = 2;
for i in 0..=maxi {
match i {
maxi => {
println!("i={} matched maxi={}",i,maxi);
}
_ => {
println!("i={} matched with _",i);
}
}
}
}
The pattern in your match arm introduces a new variable(Remember match started with a new scope) named maxi that will match any value. That's why the rust compiler emits the following warning with your first snippet.
warning: unreachable pattern
--> se_match_loop.rs:7:15
|
5 | maxi => {
| ---- matches any value
6 | println!("i={} matched maxi={}",i,maxi);
7 | } _ => {
| ^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: 1 warning emitted
Now lets consider the second one(with const),
fn main() {
const maxi: i32 = 2;
for i in 0..=maxi {
match i {
maxi => {
println!("i={} matched maxi={}",i,maxi);
}
_ => {
println!("i={} matched with _",i);
}
}
}
}
This will work as expected because constants are inlined wherever they’re used, making using them identical to simply replacing the name of the const with its value

How do I check if both variables are both Some?

I am confused about the Some(T) keyword.
I want to check for two variables, if the value is defined (not None). If that is the case, the value of this variables is processed.
I know the match pattern which works like this:
match value {
Some(val) => println!("{}", val),
None => return false,
}
If I use this pattern, it will get very messy:
match param {
Some(par) => {
match value {
Some(val) => {
//process
},
None => return false,
}
},
None => return false,
}
This can't be the right solution.
The is a possibility, to ask if the param and value is_some() That would effect code like that:
if param.is_some() && value.is_some() {
//process
}
But if I do it like that, I always have to unwrap param and value to access the values.
I thought about something like this to avoid that. But this code does not work:
if param == Some(par) && value == Some(val) {
//process
}
The idea is that the values are accessible by par and val like they are in the match version.
Is there any solution to do something like this?
If I have several Option values to match, I match on a tuple of the values:
enum Color {
Red,
Blue,
Green,
}
fn foo(a: Option<Color>, b: Option<i32>) {
match (a, b) {
(Some(Color::Blue), Some(n)) if n > 10 => println!("Blue large number"),
(Some(Color::Red), _) => println!("Red number"),
_ => (),
}
}
fn main() {
foo(Some(Color::Blue), None);
foo(Some(Color::Blue), Some(20));
}
This allows me to match the combinations that are interesting, and discard the rest (or return false, if that is what you want to do).
If your function is processing multiple Option values, and would like to discard them if they're not Some, your function could return an Option itself:
fn foo(param: Option<usize>, value: Option<usize>) -> Option<usize> {
let result = param? + value?;
Some(result)
}
This will short-circuit the function in case there's a None value stored in either param or value.
Please read the book for more information on the ? operator.
If your function can't return an Option, you can still get away with destructuring using if let or match:
let x = if let (Some(p), Some(v)) = (param, value) {
p + v
} else {
return 0;
}
let x = match (param, value) {
(Some(p), Some(v)) => p + v,
(Some(p), _) => p,
(_, Some(v) => v,
_ => return 0,
}
Please read What is this question mark operator about? for more information on the ? operator
Please read this chapter in Rust by Example for more information on destructuring multiple things at once
There's a couple more alternatives not yet listed:
If you're willing to use experimental features (and hence the nightly compiler) you can use a try block as an alternative of extracting a function.
#![feature(try_blocks)]
fn main() {
let par: Option<f32> = Some(1.0f32);
let value: Option<f32> = Some(2.0f32);
let x: Option<f32> = try { par? + value? };
println!("{:?}", x);
}
Another alternative is to use map which only applies if the value is not None
let x: Option<f32> = par.map(|p| value.map(|v| p + v));

How to access the matched value in the default case of pattern matching?

the question is about the default case.
Let's consider the following code:
fn func(x: i64) {
match x {
0 => println!("Zero"),
1 => println!("One"),
_ => {
//How to get the value here not via repeating the matched expression ?
}
};
}
Assuming you don't want to repeat the expression because it's more complex than just a variable, you can bind it to a variable:
fn func(x: i64) {
match <some complex expression> {
0 => println!("Zero"),
1 => println!("One"),
y => {
// you can use y here
}
};
}
This also works as a default case, because a variable pattern matches everything just like _ does.
_ is useful exactly when you don't want to use the value.

Conditions in a match arm without destructuring

use std::cmp::Ordering;
fn cmp(a: i32, b: i32) -> Ordering {
match {
_ if a < b => Ordering::Less,
_ if a > b => Ordering::Greater,
_ => Ordering::Equal,
}
}
fn main() {
let x = 5;
let y = 10;
println!("{}", match cmp(x, y) {
Ordering::Less => "less",
Ordering::Greater => "greater",
Ordering::Equal => "equal",
});
}
How to use match with conditions, without destructuring (because there's nothing to destructure), in the function cmp above?
The code has been adapted from the well-known example in the book which uses only if/else, however, it does not work:
src/main.rs:5:9: 5:10 error: unexpected token: `_`
src/main.rs:5 _ if a < b => Ordering::Less,
^
Could not compile `match_ordering`.
I am using rustc 1.0.0-nightly (3ef8ff1f8 2015-02-12 00:38:24 +0000).
This would work:
fn cmp(a: i32, b: i32) -> Ordering {
match (a, b) {
(a,b) if a < b => Ordering::Less,
(a,b) if a > b => Ordering::Greater,
_ => Ordering::Equal,
}
}
but it would use destructuring. Is there any other way, or is this just the most idiomatic, clean way of writing it?
You need to match on something, i.e. match { ... } isn't valid because there needs to be something between the match and the {. Since you don't care about the value itself, matching on unit, (), should be fine: match () { ... }, e.g.:
match () {
_ if a < b => Ordering::Less,
_ if a > b => Ordering::Greater,
_ => Ordering::Equal
}
(To be strict: match { _ => ... } is actually trying to parse the { ... } as the match head (i.e. the expression being matched on), and _ isn't valid at the start of an expression, hence the error.)
On idiomacity: I personally think expressing a series of conditions with short results (like this) is fine with match and a series of _ if ...s as you have done.

Resources