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).
Related
The purpose of this code is to loop from 1 to 4 and stop.
My question is why if I add or leave the semicolon in the else statement (;) it doesn't matter... the code compile just fine. What's the best approach? Add the semicolon or leave it?
fn main() {
let mut var = 1;
loop{
println!("It is now {}", var);
if var >= 4 {
println!("Finished the loop");
break;
} else {
var = var + 1;
}
}
}
In general, the trailing semicolon determines the return value of the block. If you leave the semicolon out, the return value is the value of the last expression in the block. With the semicolon included, the return value is always Rust's unit value, the empty tuple () (except when the block contains an expression that does not return, in which case the return type is the "never" type !, which does not have any values).
In this particular case, there is no semantic difference. Assignment expressions return the unit value as well, i.e. (var = var + 1) == (). However, this is more or less a coincidence. You don't actually want to return any value in that statement, so including the semicolon makes your intention much clearer.
The generated binary will be exactly be the same here but don't just think about the compiler, think about the humans reading the code too.
The absence of a semicolon at the end of the last statement of a block has an implied meaning: the value is returned from the block, the value matters.
If the value isn't used, don't return it. Put that semicolon to help humans read the code.
If you don't put that semicolon and configure Clippy to be very annoying, you'll get a warning too due to the semicolon_if_nothing_returned rule.
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.
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.
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;
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