For example:
enum FooBar {
Bar(Vec<int>),
Other
}
fn main() {
let default:&[int] = [];
let x = Bar(Vec::from_slice([1, 2, 3]));
let y = match(x) {
Bar(z) => z.slice(0, z.len()),
_ => default
};
println!("{}", y);
}
In this example the slice is not valid because of the lifetime on z; but we know that the actual data here (x) is valid for the entire block.
Is there some 'a syntax you can use here to help hint this to compiler? If so, how do you do it?
(I believe I've seen some kind of 'a match { } or match x 'a { } / something syntax in the past, but I can't find any examples now that I'm looking)
Sure, there is some syntax, though it is not as explicit on lifetimes as you mean and in fact it is more general. By doing match as you do you are actually moving x into the match, so it is consumed. No wonder that z.slice(...) can't escape the block. But you can avoid moving x into the match by using reference patterns (note the ref before z):
let default: &[int] = [];
let x = Bar(vec![1, 2, 3]);
let y = match x {
Bar(ref z) => z.slice(0, z.len()),
Other => default
};
println!("{}", y);
This way x is not moved into match block - its internals are borrowed instead. This program compiles and prints out [1, 2, 3].
Related
I was doing an exercise on exercism with Rust and came across a community solution where the implementation of the given user confused me.
pub struct Position(pub i16, pub i16);
impl Position {
pub fn manhattan(&self) -> i16 {
let Position(x, y) = self;
x.abs() + y.abs()
}
}
What I do not understand is:
let Position(x, y) = self;
x.abs() + y.abs()
As I understand it, I am initializing a struct of Position, but how am I initializing it without setting it equal to a variable? Further more, how am I then able to suddenly have access to the arguments?
What you see here is called destructuring, and is actually creating variables x and y from self.
In this case, if you were to take this line of code:
let Position(x, y) = self;
What this is actually saying is equilalent to this:
let x = &self.0;
let y = &self.1;
You can think of the Position(x, y) part of the assignment as a pattern. You will see pattern matching in many places in Rust, most commonly in match statements. For example, unwrapping a variable of type Option<String> might look like:
match some_optional_string {
Some(value) => println!("Got value: {value}"),
None => println!("Got no value")
};
Pattern matching also appears in conditions as well.
if let Some(value) = some_optional_string {
println!("Got value: {value}");
}
Another way to think of the particular example that you are referring to, is to replace self with its actual value. Say for example self was initialized with the values 3 and 4, this might look like so:
let some_position = Position(3, 4);
Now if you were to call some_position.manhatten(), self is equivalent to a &Position(3, 4)
If you replace all uses of self in the function with the value:
let Position(x, y) = &Position(3, 4);
x.abs() + y.abs()
(This won't actually compile because of lifetimes, but this is beside the point)
You can see more clearly now that Position(x, y) matches &Position(3, 4) but assigning x and y to &3 and &4
I saw you were also learning Haskell, which has a very similar concept. In haskell you could have a function that took in a Maybe value, and have different definitions based on which it matched.
someFunc :: Maybe String -> String
someFunc (Just value) = value
someFunc Nothing = "I'm a different string"
Which has the same concept of destructuring or matching.
Hopefully this rambling makes sense!
I'm working on a rust project written a couple of years ago, and have come across this piece of code, which is literally:
let mut values = vec![];
for x in maybe_values {
if let Some(x) = x {
values.push(Arc::new(x));
}
}
I understand that "if let" introduces a pattern-matching if (Which seems to be a poor re-use of the keyword "let", but I will get over that - If anyone can help me with a mental mnemonic to make sense of "let" here, please do!).
But what is the test Some(x) = x doing?
From my testing, it seems to be a trick/idiom to both a) test that the loop variant 'x' is Some(), and also b) end up with the unwrap()ped value in x.
But I can't fully explain it to myself, and can't find reference to this being an idiom anywhere.
Hope you can help my Rust education path. Thanks.
This is a shorthand for using a full match statement when you only care about matching a single use case.
So this block of code:
if let x = y {
foo();
} else {
bar();
}
Is equivalent to using a full match:
match y {
x => {
foo();
}
_ => {
bar();
}
}
For your specific case, it is equivalent to this. The inner x uses the same name as the outer variable which can be confusing, but they are two separate values.
let mut values = vec![];
for x in maybe_values {
match x {
Some(y) => values.push(Arc::new(y)),
_ => {},
}
}
There are two completely different variables in play here. It's equivalent to.
let mut values = vec![];
for x_1 in maybe_values {
if let Some(x_2) = x_1 {
values.push(Arc::new(x_2));
}
}
In Rust, the right-hand side of a let is evaluated with the left-hand variable not in scope, so when the if let is evaluated, the outer x is still in-scope. Then, if it's a Some value, we make a new variable x which contains the inside of the Option. This variable shadows the previous x, making it inaccessible inside the if statement (in the same way that a function argument called x would render a global variable named x inaccessible by shadowing).
What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, since they have mismatched types (where i is &32 and i is i32). But how does &i convert i into i32?
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for &i in list {
if i > largest {
largest = i;
}
}
largest
}
fn main() {
let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
println!("The largest number is: {}", largest(&hey));
}
Playground
It seems like it is somehow dereferencing, but then why in the below code, is it not working?
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
It says:
4 | hey = &&x;
| ^^^ expected i32, found &&i32
|
= note: expected type `i32`
found type `&&i32`
So normally when you use for i in list, the loop variable i would be of type &i32.
But when instead you use for &i in list, you are not dereferencing anything, but instead you are using pattern matching to explicitly destructure the reference and that will make i just be of type i32.
See the Rust docs about the for-loop loop variable being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers.
An other way to solve this, would be to just keep i as it is and then comparing i to a reference to largest, and then dereferencing i before assigning to largest:
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for i in list {
if i > &largest {
largest = *i;
}
}
largest
}
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
This simply doesn't work, because here you are assigning hey, which is an i32, to a reference to a reference to an i32. This is quite unrelated to the pattern matching and destructuring in the loop variable case.
This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then y has the type T → it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use & on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).
Related questions:
Iterating over a slice's values instead of references in Rust?
Why is & needed to destructure a list of tuples during iteration?
I'm wondering if someone can help me understand why this program behaves as it does:
fn main() {
let mut x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&mut y);
println!("GOT {}",*y);
}
}
This program compiles under rust 1.35.0 (both 2015 and 2018 editions), and prints
GOT 456
But, I'm confused what's going on here. I'm guessing that this is an example of an auto-dereference. So, in reality, it looks like this:
fn main() {
let mut x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&mut *y);
println!("GOT {}",*y);
}
}
Is that it?
This is a case of deref coercion, but one that is obfuscated by a few other unnecessary parts of the code. The following improvements should be made here:
The mut modifier on variable x is not needed because it is never modified.
The borrow of y in Box::new(&mut y) does not have to be mutable because the variable holds an immutable reference.
The println! implementation also knows to print values behind references, so the explicit * is not needed.
Then, we get the following code:
fn main() {
let x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&y);
println!("GOT {}", y);
}
}
y is a variable of type Box<&i32> which is initially bound to a box created in the outer scope. The subsequent assignment to a new box works because the &y, of type &Box<&i32>, is coerced to &&i32, which can then be put in the box by automatically dereferencing the first borrow. This coercion is required because the variable x can only be assigned values of the same Box<&i32> type.
The lifetime of the reference inside both boxes also ended up being the same, because they refer to the same value in x.
See also:
What is the relation between auto-dereferencing and deref coercion?
What is the purpose of & in the code &i in list? If I remove the &, it produces an error in largest = i, since they have mismatched types (where i is &32 and i is i32). But how does &i convert i into i32?
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for &i in list {
if i > largest {
largest = i;
}
}
largest
}
fn main() {
let hey = vec![1, 3, 2, 6, 90, 67, 788, 12, 34, 54, 32];
println!("The largest number is: {}", largest(&hey));
}
Playground
It seems like it is somehow dereferencing, but then why in the below code, is it not working?
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
It says:
4 | hey = &&x;
| ^^^ expected i32, found &&i32
|
= note: expected type `i32`
found type `&&i32`
So normally when you use for i in list, the loop variable i would be of type &i32.
But when instead you use for &i in list, you are not dereferencing anything, but instead you are using pattern matching to explicitly destructure the reference and that will make i just be of type i32.
See the Rust docs about the for-loop loop variable being a pattern and the reference pattern that we are using here. See also the Rust By Example chapter on destructuring pointers.
An other way to solve this, would be to just keep i as it is and then comparing i to a reference to largest, and then dereferencing i before assigning to largest:
fn largest(list: &[i32]) -> i32 {
println!("{:?}", list);
let mut largest = list[0];
for i in list {
if i > &largest {
largest = *i;
}
}
largest
}
fn main() {
let mut hey: i32 = 32;
let x: i32 = 2;
hey = &&x;
}
This simply doesn't work, because here you are assigning hey, which is an i32, to a reference to a reference to an i32. This is quite unrelated to the pattern matching and destructuring in the loop variable case.
This is the effect of destructuring. I won't completely describe that feature here, but in short:
In many syntax contexts (let bindings, for loops, function arguments, ...) , Rust expects a "pattern". This pattern can be a simple variable name, but it can also contain some "destructuring elements", like &. Rust will then bind a value to this pattern. A simple example would be something like this:
let (a, b) = ('x', true);
On the right hand side there is a value of type (char, bool) (a tuple). This value is bound to the left hand pattern ((a, b)). As there is already a "structure" defined in the pattern (specifically, the tuple), that structure is removed and a und b bind to the tuple's elements. Thus, the type of a is char and the type of b is bool.
This works with a couple of structures, including arrays:
let [x] = [true];
Again, on the right side we have a value of type [bool; 1] (an array) and on the left side we have a pattern in the form of an array. The single array element is bound to x, meaning that the type of x is bool and not [bool; 1]!
And unsurprisingly, this also works for references!
let foo = 0u32;
let r = &foo;
let &c = &foo;
Here, foo has the type u32 and consequently, the expression &foo has the type &u32. The type of r is also &u32, as it is a simple let binding. The type of c is u32 however! That is because the "reference was destructured/removed" by the pattern.
A common misunderstanding is that syntax in patterns has exactly the opposite effect of what the same syntax would have in expressions! If you have a variable a of type [T; 1], then the expression [a] has the type [[T; 1]; 1] → it adds stuff. However, if you bind a to the pattern [c], then y has the type T → it removes stuff.
let a = [true]; // type of `a`: `[bool; 1]`
let b = [a]; // type of `b`: `[[bool; 1]; 1]`
let [c] = a; // type of `c`: `bool`
This also explains your question:
It seems like it is somehow dereferencing, but then why in the below code, it is not working?
fn main() {
let mut hey:i32 = 32;
let x:i32 = 2;
hey = &&x;
}
Because you use & on the expression side, where it adds a layer of references.
So finally about your loop: when iterating over a slice (as you do here), the iterator yields reference to the slice's elements. So in the case for i in list {}, i has the type &i32. But the assignment largest = i; requires a i32 on the right hand side. You can achieve this in two ways: either dereference i via the dereference operator * (i.e. largest = *i;) or destructure the reference in the loop pattern (i.e. for &i in list {}).
Related questions:
Iterating over a slice's values instead of references in Rust?
Why is & needed to destructure a list of tuples during iteration?