I'm new to Rust and I don't understand the following piece of code:
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
Explanation from the Rust site:
You'll also notice we added an asterisk (*) in front of y, making it *y, this is because y is a &mut reference. You'll need to use astrisks [sic] to access the contents of a reference as well.
If *y is a reference, why does the following code work
fn main() {
let mut x = 5;
{
let y = &mut x;
println!("{}", y);
}
}
I know I'm not modifying the value here, but what is the difference and why
would y += 1; not work?
If *y is a reference
*y is not a reference. y is a reference; *y dereferences y, allowing you access to the referred-to value.
what is the difference [between += and println!]
println! is a macro that automatically references the arguments given to it. In addition, the Display trait (used via {} in the format string) is implemented for all references to types that themselves implement Display (impl<'a, T> Display for &'a T where T: Display + ?Sized).
Thus, println!("{}", y); is actually printing out a reference to a reference to a value. Those intermediate references are automatically dereferenced due to the implementation of Display.
+=, on the other hand, is implemented via the AddAssign trait. The standard library only implements adding an integer type to itself (impl AddAssign<i32> for i32). That means that you have to add an appropriate level of dereferencing in order to get both sides to an integer.
Related
This code doesn't compile. But it fails on the last line marked Err, not the line marked Ok. Why can we assign a mutable reference to an immutable reference type but not use it after the assignment?
fn main() {
let mut x = 10;
let mut y = 20;
let mut r = &x;
r = &mut y; //Ok
*r = 30; //Err
}
Why can we ... not use it after the assignment?
The variable r is an immutable reference of type &i32; it does not have mutable access to the referenced value. So it makes sense the compiler would reject your attempt to assign through it.
Why can we assign a mutable reference to an immutable reference type ...?
Why wouldn't you be able to downgrade a mutable reference into an immutable one? The latter is a strict subset of the former. If you were asking about the technicalities instead of the practicalities, its because &mut T to &T is a supported coercion.
If we add explicit types to your code as inferred by the compiler:
fn main() {
let mut x: i32 = 10;
let mut y: i32 = 20;
let mut r: &i32 = &x;
r = &mut y; //Ok
*r = 30; //Err
}
We see that r has type &i32 and not &mut i32, so of course we can't use r to modify the referenced value.
Why can we still do r = &mut y? Simply because we can always use a &mut reference anywhere a & reference is expected (because &mut T implements Deref<Target=T>, allowing coercion to happen).
Presume we have the following code, where I defined a closure named closure. Within this closure, I want to use the outer x by immutable reference (&T), and at the same time, using y by taking ownership. How can I do that? If I use move, all the outer variables that used in the closure will be moved into the closure. And also here the outer variable y is copyable.
let x: i32 = 1;
let y: i32 = 2;
let closure = || {
println!("{}", x); // make sure x is used by &T.
// println!("{}", y); // how can I use y by taking its ownership?
};
closure();
Note that capturing by moving a reference is equal to capturing by reference.
When you add a move keyword to the closure, yes, everything is captured by moving. But you can move a reference instead, which is what a closure without a move keyword does.
let x: i32 = 1;
let y: i32 = 2;
let closure = {
let x = &x;
move || {
println!("{}", x); // borrowing (outer) x
println!("{}", y); // taking the ownership of y
}
};
closure();
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?
This question already has answers here:
What's the difference between placing "mut" before a variable name and after the ":"?
(4 answers)
Closed 6 years ago.
What is the difference between
let y = &mut 5;
*y += 1;
let x = *y + 1;
and
let mut y = 5;
y += 1;
let x = y + 1;
They return the same result via println!, but I can't decide which one is preferable.
Given your simple example of binding a variable to one or the other, then calling println! locally, there really isn't much difference in the result (as you've noted).
A mutable value vs a mutable reference becomes more clear when you cross function boundaries. Have a look at this code:
fn main() {
let mut x = &mut 5;
do_work(x);
println!("{}", x);
}
fn do_work(n: &mut u32) {
*n += 5;
}
What do you think it prints? Here it is on the playground
Now look at this code:
fn main() {
let mut x = 5;
do_work(x);
println!("{}", x);
}
fn do_work(mut n: u32) {
n += 5;
}
What do you think this prints? Here it is on the playground
The answers are:
The top code block prints 10. The bottom code block prints 5.
Using the mutable reference means you're referencing the place in memory where the variable x is stored. Across function boundaries, you're able to change the value stored in memory there. When the method returns and println! hits.. the value of x is updated.
In this specific example, x is a u32, which implements the Copy trait. When you pass x into the do_work method, a copy of x is made. In the body of the do_work method, n += 5 adds 5 to the copy .. and does not reference the original block of memory at all.
...can't decide which one is preferable.
That depends entirely on use-case. Do you need to reference the original memory when crossing a function boundary? If you have marked your variable as mutable, there is a high chance that you do want to reference the original memory in the hopes of updating it. In that case, you would use a mutable reference. If you're just mutating a variable locally within a function.. then you won't require a reference.
Despite thoroughly reading the documentation, I'm rather confused about the meaning of the & and * symbol in Rust, and more generally about what is a Rust reference exactly.
In this example, it seems to be similar to a C++ reference (that is, an address that is automatically dereferenced when used):
fn main() {
let c: i32 = 5;
let rc = &c;
let next = rc + 1;
println!("{}", next); // 6
}
However, the following code works exactly the same:
fn main() {
let c: i32 = 5;
let rc = &c;
let next = *rc + 1;
println!("{}", next); // 6
}
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
My understanding so far, is that, inserting * in front of a Rust reference dereferences it, but the * is implicitly inserted anyway so you don't need to add it (while in C++, it's implicitly inserted and if you insert it you get a compilation error).
However, something like this doesn't compile:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = rc + 1;
}
println!("{}", next);
}
error[E0369]: binary operation `+` cannot be applied to type `&mut i32`
--> src/main.rs:6:16
|
6 | next = rc + 1;
| ^^^^^^
|
= note: this is a reference to a type that `+` can be applied to; you need to dereference this variable once for this operation to work
= note: an implementation of `std::ops::Add` might be missing for `&mut i32`
But this works:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = *rc + 1;
}
println!("{}", next); // 6
}
It seems that implicit dereferencing (a la C++) is correct for immutable references, but not for mutable references. Why is this?
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
A reference in C++ is not the same as a reference in Rust. Rust's references are much closer (in usage, not in semantics) to C++'s pointers. With respect to memory representation, Rust's references often are just a single pointer, while C++'s references are supposed to be alternative names of the same object (and thus have no memory representation).
The difference between C++ pointers and Rust references is that Rust's references are never NULL, never uninitialized and never dangling.
The Add trait is implemented (see the bottom of the doc page) for the following pairs and all other numeric primitives:
&i32 + i32
i32 + &i32
&i32 + &i32
This is just a convenience thing the std-lib developers implemented. The compiler can figure out that a &mut i32 can be used wherever a &i32 can be used, but that doesn't work (yet?) for generics, so the std-lib developers would need to also implement the Add traits for the following combinations (and those for all primitives):
&mut i32 + i32
i32 + &mut i32
&mut i32 + &mut i32
&mut i32 + &i32
&i32 + &mut i32
As you can see that can get quite out of hand. I'm sure that will go away in the future. Until then, note that it's rather rare to end up with a &mut i32 and trying to use it in a mathematical expression.
This answer is for those looking for the basics (e.g. coming from Google).
From the Rust book's References and Borrowing:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
These ampersands represent references, and they allow you to refer to some value without taking ownership of it [i.e. borrowing].
The opposite of referencing by using & is dereferencing, which is accomplished with the dereference operator, *.
And a basic example:
let x = 5;
let y = &x; //set y to a reference to x
assert_eq!(5, x);
assert_eq!(5, *y); // dereference y
If we tried to write assert_eq!(5, y); instead, we would get a compilation error can't compare `{integer}` with `&{integer}`.
(You can read more in the Smart Pointers chapter.)
And from Method Syntax:
Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.
Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:
p1.distance(&p2);
(&p1).distance(&p2);
From the docs for std::ops::Add:
impl<'a, 'b> Add<&'a i32> for &'b i32
impl<'a> Add<&'a i32> for i32
impl<'a> Add<i32> for &'a i32
impl Add<i32> for i32
It seems the binary + operator for numbers is implemented for combinations of shared (but not mutable) references of the operands and owned versions of the operands. It has nothing to do with automatic dereferencing.