I am playing around with Rust references:
fn main() {
let str = String::from("Hallo");
let &x = &str;
}
This produces the following error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:3:9
|
3 | let &x = &str;
| ^-
| ||
| |hint: to prevent move, use `ref x` or `ref mut x`
| cannot move out of borrowed content
What is going on here?
Adding to wiomoc's answer: depending on what language(s) you've previously known, variable declaration in Rust might be a little different. Whereas in C/C++ you explicitly have to declare that you want a pointer/reference variable:
int *p = &other_int;
In Rust it's enough to just use let, so the above would in Rust be
let p = &other_int;
and when you write
let &s = &string;
It pattern-matches that, so the Rust compiler reads it roughly as "I know I have a reference, and I want to bind whatever it is referring to to the name p". If you're not familiar with pattern-matching, a more obvious example (that works in Rust as well) would be
let point = (23, 42);
let (x, y) = point;
The second line unpacks the right-hand side to match the left-hand side (both are tuples of two values) and binds the variable names on the left to the values at the same position in the structure on the right. In the case above, it's less obvious that it's matching your "structural description".
The result of let &x = &str;, i.e. "I know &str is a reference, please bind whatever it refers to to the variable x" means that you're trying to have x be the same as str, when at that line all you have is a borrowed reference to str. That's why the compiler tells you you can't create an owned value (which x would be, because it's not being created as a reference) from a reference.
You dont need that &at let x
let str = String::from("Hallo");
let x = &str;
Or if you want to declare the type manually
let string = String::from("Hallo");
let x: &str = &string;
Related
In the documentation for std::iter::Iterator::filter() it explains that values are passed to the closure by reference, and since many iterators produce references, in that case the values passed are references to references. It offers some advice to improve ergonomics, by using a &x pattern to remove one level of indirection, or a &&x pattern to remove two levels of indirection.
However, I've found that this second pattern does not compile if the item being iterated does not implement Copy:
#[derive(PartialEq)]
struct Foo(i32);
fn main() {
let a = [Foo(0), Foo(1), Foo(2)];
// This works
let _ = a.iter().filter(|&x| *x != Foo(1));
// This also works
let _ = a.iter().filter(|&x| x != &Foo(1));
// This does not compile
let _ = a.iter().filter(|&&x| x != Foo(1));
}
The error you get is:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:14:30
|
14 | let _ = a.iter().filter(|&&x| x != Foo(1));
| ^^-
| | |
| | data moved here
| | move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
| help: consider removing the `&`: `&x`
Does this mean that if I use the &&x destructuring pattern, and the value is Copy, Rust will silently copy every value I am iterating over? If so, why does that happen?
In Rust, function or closure arguments are irrefutable patterns.
In the Rust reference, it says:
By default, identifier patterns bind a variable to a copy of or move
from the matched value depending on whether the matched value
implements Copy.
So, in this case:
let _ = a.iter().filter(|&x| *x != Foo(1));
the closure is being passed a reference to a reference to the item being iterated; therefore x is bound to a copy of a reference to the item. You can always copy a reference (it is basically a no-op) so this always succeeds.
In this case:
let _ = a.iter().filter(|&&x| x != Foo(1));
x is being bound to a copy of the item itself - which fails if the item is not Copy.
The reference also says:
This can be changed to bind to a reference by using the ref keyword,
or to a mutable reference using ref mut.
That's not so useful in this case though: &&ref x results in x being a reference to the item, the same as if you had used &x.
Does this mean that if I use the &&x destructuring pattern, and the value is Copy, Rust will silently copy every value I am iterating over?
Yes, that's correct, although the compiler backend might optimize the copying away.
If so, why does that happen?
Writing & before a pattern dereferences it. This copies the value it refers to, because a reference only borrows its value, so it can't move the value.
Example:
#[derive(Copy, Clone)]
struct Foo(i32);
let foo: Foo = Foo(5); // value is owned by foo
let borrow: &Foo = &foo; // value is borrowed
let bar: Foo = *borrow; // value is copied, the copy is owned by bar
// the original value is still owned by foo
Your first example is a bit special:
let _ = a.iter().filter(|&x| *x != Foo(1));
This seems at first as if it should require the Copy trait because x is dereferenced twice, first in the pattern, and then in the comparison.
However, the comparison is done by the PartialEq trait, which takes its arguments by reference. So the above is desugared to:
let _ = a.iter().filter(|&x| PartialEq::eq(&*x, &Foo(1)));
Which works because &* cancel each other out. Hence, x is only dereferenced once (in the pattern).
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?
I'm trying to understand how & and ref correspond. Here's an example where I thought these were equivalent, but one works and the other doesn't:
fn main() {
let t = "
aoeu
aoeu
aoeu
a";
let ls = t.lines();
dbg!(ls.clone().map(|l| &l[..]).collect::<Vec<&str>>().join("\n")); // works
dbg!(ls.clone().map(|ref l| l[..]).collect::<Vec<&str>>().join("\n")); // doesn't work
dbg!(ls.clone().map(|ref l| &l[..]).collect::<Vec<&str>>().join("\n")); // works again!
}
From the docs:
// A `ref` borrow on the left side of an assignment is equivalent to
// an `&` borrow on the right side.
let ref ref_c1 = c;
let ref_c2 = &c;
println!("ref_c1 equals ref_c2: {}", *ref_c1 == *ref_c2);
What would the equivalent to |l| &l[..] be with |ref l|? How does it correspond to the assignment examples in the docs?
Taking a look at the docs page for Lines(The iterator adapter for producing lines from a str), we can see that the item produced by it is:
type Item = &'a str;
Therefore the following happens when trying to do the "doesn't work" version:
dbg!(ls.clone().map(|ref l| l[..]).collect::<Vec<&str>>().join("\n")); # doesn't work
//Can become:
let temp = ls
.clone()
.map(|ref l| l[..])
.collect::<Vec<&str>>()
.join("\n");
println!("{}", temp);
Here we can see a crucial problem. l if of type &&str (Which I will explain below) so indexing into it will create a str, which is unsized and therefore cannot be outside of a pointer of some sort.
Now, onto the real thing you wanted to learn: What a ref pattern does:
When doing pattern matching or destructuring via the let binding, the ref keyword can be used to take references to the fields of a struct/tuple.
What this does is the following:
When we have let ref x = y, we take a reference to y.
When pattern matching on something (Like in your closure arguments you showed) we have a slightly different effect: the value under the reference is moved into the scope and then taken reference to while exposing a way to take the value under the reference. For example:
fn foo(ref x: String) {}
let y: fn(String) = foo;
This works because what is essentially being done is this:
fn foo(x: String) {
let x: &String = &x;
}
So what ref x does is take ownership of x and produce a reference to it.
On the other hand
When we have let &x = y we move a value out of y.
This is the opposite of ref, in that we take ownership of the value under y if we can. For example:
let x = 2;
let y = &x;
let &z = y; //Ok, we're moving a `Copy` type
This is only ok for copy types though as though this isn't exactly the same as let x = *y which would work for owned Boxes.
I have the following code:
fn main() {
let mut vec = Vec::new();
vec.push(String::from("Foo"));
let mut row = vec.get_mut(0).unwrap();
row.push('!');
println!("{}", vec[0])
}
It prints out "Foo!", but the compiler tells me:
warning: variable does not need to be mutable
--> src/main.rs:4:9
|
4 | let mut row = vec.get_mut(0).unwrap();
| ----^^^
| |
| help: remove this `mut`
Surprisingly, removing the mut works. This raises a few questions:
Why does this work?
Why doesn't this work when I use vec.get instead of vec.get_mut, regardless of whether I use let or let mut?
Why doesn't vec work in the same way, i.e. when I use let vec = Vec::new(), why can't I call vec.push()?
vec.get_mut(0) returns an Option<&mut String>, so when you unwrap that value you will have a mutable borrow of a String. Remember, that a let statement's left side is using pattern matching, so when your pattern is just a variable name you essentially say match whatever is on the right and call it name. Thus row matches against &mut String so it already is mutable.
Here's a much simpler and more straightforward example to illustrate the case (which you can try in the playground):
fn main() {
let mut x = 55i32;
dbg!(&x);
let y = &mut x; // <-- y's type is `&mut i32`
*y = 12;
dbg!(&x);
}
I am playing with Rust, and I'm trying to access the first command line argument with this code:
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let dir = args[1];
}
And I get this error:
error[E0507]: cannot move out of indexed content
--> src/main.rs:5:15
|
5 | let dir = args[1];
| --- ^^^^^^^ cannot move out of indexed content
| |
| hint: to prevent move, use `ref dir` or `ref mut dir`
Or in later versions of Rust:
error[E0507]: cannot move out of index of `std::vec::Vec<std::string::String>`
--> src/main.rs:5:15
|
5 | let dir = args[1];
| ^^^^^^^
| |
| move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&args[1]`
If I change it to let ref dir, it compiles, but I don't grok what's going on. Could someone explain what "indexed content" means?
When you use an index operator ([]) you get the actual object at index location. You do not get a reference, pointer or copy. Since you try to bind that object with a let binding, Rust immediately tries to move (or copy, if the Copy trait is implemented).
In your example, env::args() is an iterator of Strings which is then collected into a Vec<String>. This is an owned vector of owned strings, and owned strings are not automatically copyable.
You can use a let ref binding, but the more idiomatic alternative is to take a reference to the indexed object (note the & symbol):
use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let ref dir = &args[1];
// ^
}
Implicitly moving out of a Vec is not allowed as it would leave it in an invalid state — one element is moved out, the others are not. If you have a mutable Vec, you can use a method like Vec::remove to take a single value out:
use std::env;
fn main() {
let mut args: Vec<_> = env::args().collect();
let dir = args.remove(1);
}
See also:
What is the return type of the indexing operation?
For your particular problem, you can also just use Iterator::nth:
use std::env;
fn main() {
let dir = env::args().nth(1).expect("Missing argument");
}
The accepted answer has already given the solution. I would like to explain this problem on a semantic level as a complement.
The rule is: A borrowed value can't be moved out. See this: E0507
[] operator came from the Index trait, whose function signature is:
fn index(&self, index: I) -> &<Vec<T, A> as Index<I>>::Output
As you can see, it return a reference, not own the value. Moving it out break the rule mentioned above.