This question already has an answer here:
Why is this match pattern unreachable when using non-literal patterns?
(1 answer)
Closed 7 months ago.
#[allow(dead_code)]
fn print_grid(empty: (usize,usize), goal: (usize,usize), (w,h): (usize,usize)) {
for y in 0..h {
for x in 0..w {
let s: String = match (x,y) {
empty => "_".to_string(),
goal => "G".to_string(),
(0,0) => "*".to_string(),
_ => ".".to_string()
};
print!("{s} ");
}
println!();
}
}
This match statement generates an unreachable pattern warning:
warning: unreachable pattern
--> src/lib.rs:75:17
|
74 | empty => "_".to_string(),
| ----- matches any value
75 | goal => "G".to_string(),
| ^^^^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
And indeed, when I use this function, any pattern will lead to "_" being printed.
It may be obvious but I can't figure it out. Is this an error from Rust (I doubt it)? Is there something important I'm missing?
Patterns in Rust can only compare against the shape of the data or literal values. So it's possible to pattern match against (for instance) the number 1 since that's a literal in the code, but not against a variable.
match (x,y) {
empty => "_".to_string(),
goal => "G".to_string(),
(0,0) => "*".to_string(),
_ => ".".to_string()
};
The names empty and goal here have no relation to the names empty and goal you already declared. They're new variables shadowing the old ones. So the first pattern will match anything and will assign it to a new variable called empty.
To compare against variables, use a guard clause.
match (x,y) {
(0,0) => "*".to_string(),
x if x == empty => "_".to_string(),
x if x == goal => "G".to_string(),
_ => ".".to_string()
};
Related
This question already has an answer here:
Why is this match pattern unreachable when using non-literal patterns?
(1 answer)
Closed 7 months ago.
#[allow(dead_code)]
fn print_grid(empty: (usize,usize), goal: (usize,usize), (w,h): (usize,usize)) {
for y in 0..h {
for x in 0..w {
let s: String = match (x,y) {
empty => "_".to_string(),
goal => "G".to_string(),
(0,0) => "*".to_string(),
_ => ".".to_string()
};
print!("{s} ");
}
println!();
}
}
This match statement generates an unreachable pattern warning:
warning: unreachable pattern
--> src/lib.rs:75:17
|
74 | empty => "_".to_string(),
| ----- matches any value
75 | goal => "G".to_string(),
| ^^^^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
And indeed, when I use this function, any pattern will lead to "_" being printed.
It may be obvious but I can't figure it out. Is this an error from Rust (I doubt it)? Is there something important I'm missing?
Patterns in Rust can only compare against the shape of the data or literal values. So it's possible to pattern match against (for instance) the number 1 since that's a literal in the code, but not against a variable.
match (x,y) {
empty => "_".to_string(),
goal => "G".to_string(),
(0,0) => "*".to_string(),
_ => ".".to_string()
};
The names empty and goal here have no relation to the names empty and goal you already declared. They're new variables shadowing the old ones. So the first pattern will match anything and will assign it to a new variable called empty.
To compare against variables, use a guard clause.
match (x,y) {
(0,0) => "*".to_string(),
x if x == empty => "_".to_string(),
x if x == goal => "G".to_string(),
_ => ".".to_string()
};
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, ¤t| 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?
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).
This question already has an answer here:
What does the '#' symbol do in Rust?
(1 answer)
Closed 2 years ago.
I'm new in Rust and while learning the standard library I found the expression Some(x # 6..=10) in a match example. What does x # 6..=10 mean?
something # pattern is a way to do the pattern matching. Normally a match branch creates variables for parts of the matched value. But something # pattern creates a variable something and moves or copies the whole value into it.
The syntax low ..= high allows you to match on all numbers within the range from low to high (inclusive). The # in pattern match expressions allows you to bind a variable to the matched value. Here's an example to illustrate their uses:
fn log_num(maybe_num: Option<i32>) {
match maybe_num {
None => println!("didn't get a number"),
Some(x # 0..=5) => println!("got number {} between 0-5", x),
Some(y # 6..=10) => println!("got number {} between 6-10", y),
Some(z) => println!("got number {} larger than 10", z),
}
}
fn main() {
log_num(None);
log_num(Some(3));
log_num(Some(7));
log_num(Some(15));
}
playground
This is a form of pattern matching, specifically # bindings. In the form...
let y = Some(3);
if let Some(x # 6..=10) = y {
// ...
}
... the variable y needs to be a Some(...) to match, and the inner value will be assigned to x if it is within the range 6 to 10 (inclusive). In the example above, the if-block will not be executed, because while y destructures to a Some(...), the inner value does not fit the pattern and therefor x does not bind.
A pull request has been done with a new test for the Rust compiler. It verifies that a strange line can compile:
fn main() {
let val = !((|(..):(_,_),__#_|__)((&*"\\",'#')/**/,{})=={&[..=..][..];})//
;
assert!(!val);
}
What does this line do exactly?
Let's break it down! First, I reformatted the line to somewhat increase "readability".
let val = !(
(
|(..): (_, _), __#_| __
)(
(
&*"\\",
'#'
) /**/,
{}
)
==
{
&[..=..][..];
}
)//
;
It starts with let val = and ends with //<newline>;. So it's a simple let-binding of the form let val = ⟨v⟩;. Let's discuss what ⟨v⟩ does:
A negation via the not operator: !( ⟨_⟩ )
A comparison via ==: ⟨lhs⟩ == ⟨rhs⟩
⟨lhs⟩: a function call of a closure ( ⟨closure⟩ )( ⟨args⟩ )
⟨closure⟩: a closure definition |⟨first_param⟩, ⟨second_param⟩| ⟨body⟩
⟨first_param⟩: (..): (_, _). This parameter has a type annotation (_, _) meaning that it is a 2-tuple. The pattern (where normally, you would find a single name) is (..) which means: a tuple, but ignore all elements of it.
⟨second_param⟩: __#_. This is a pattern usually known from match bindings: name # pattern. So the actual pattern is _ (which doesn't bind anything) and the value is bound via # to the name __ (two underscores, which is a kind of valid identifier).
⟨body⟩: __. This is just the identifier which we bound the second parameter to. So the closure is basically equivalent to |_, x| x.
⟨args⟩: a list of two arguments with an inline comment /**/ in between: ⟨first_arg⟩/**/, ⟨second_arg⟩
⟨first_arg⟩: (&*"\\", '#'). This is simply a 2-tuple where the first element is a string containing a backslash and the second is the char '#'. The &* for the first element cancels out.
⟨second_arg⟩: {}. This is an empty block which has the type (). So as second argument, a unit is passed.
⟨rhs⟩: a braced block with one statement inside: { ⟨stmt⟩; }. Note that this is a statement, with a semicolon. This means the result is not returned from the block. Instead the block returns () just as the empty block {}.
⟨stmt⟩: an indexing expression { &⟨collection⟩[⟨index⟩] }.
⟨collection⟩: [..=..]. This is an array with one element. The element is ..= .. which is a RangeToInclusive where end of the range is the RangeFull written ...
⟨index⟩: ... This is just the RangeFull again.
So in summary: we compare the result of calling a closure to a braced block which evaluates to (). The closure is basically |_, x| x and the second argument we pass to it is {} (which evaluates to ()), so the whole closure calling expression evaluates to ().
This means the whole thing is equivalent to:
let val = !( () == () );, which is equivalent to:
let val = !( true );, which is equivalent to:
let val = false;