what happens to a rust mutable value after each assignment [duplicate] - rust

This question already has answers here:
Does Rust free up the memory of overwritten variables?
(3 answers)
When does Rust drop the value in case of reassignment? [duplicate]
(1 answer)
Closed 15 days ago.
Here are two examples of dynamic mutable value.
pub fn main() {
let mut x = String::from("Hello");
println!("{}", x);
x = format!("{x}, world!");
println!("{}", x);
}
So as you can see, we have a mutable variable x. x gets borrowed by format! & turns to a new value that is then assigned back to x.
pub fn main() {
let mut x = String::from("Hello, world!");
println!("{}", x);
x = String::from("Lorem, ipsum!");
println!("{}", x);
}
My real problem is this code, where the value assigned to x has no connection with it's initial value. Variables can only take owner-ship over a single value, so how does Rust keep track of "Hello, world!" & "Lorem, ipsum!"? Exactly what happens to mutable values after assignments?
My guess is that it checks if the value getting assigned to depends on the first one, if yes, it won't drop it.

Related

Rust mutable variable and String [duplicate]

This question already has answers here:
When does Rust drop the value in case of reassignment? [duplicate]
(1 answer)
Does Rust free up the memory of overwritten variables?
(3 answers)
Closed 2 months ago.
I have the following piece of code
{
let mut a = String::from("Foo");
a = String::from("Bar");
}
I'm wondering when will the first String be freed is it when I assign a to a different String ? or is it when the scope ends ?
You can easily test this:
struct B(&'static str);
impl Drop for B {
fn drop(&mut self) {
println!("{} B dropped", self.0)
}
}
fn main() {
{
let mut b = B("first");
println!("{} B created", b.0);
b = B("second");
println!("{} B reasigned", b.0);
}
}
This outputs:
first B created
first B dropped
second B reasigned
second B dropped
So the first instance of B is dropped when the variable is re-assigned. The second one is dopped at the end of the function.
Playground link to try it yourself

Immutable variables in RUST can be reassigned using destructuring? [duplicate]

This question already has an answer here:
In Rust, what's the difference between "shadowing" and "mutability"?
(1 answer)
Closed 2 years ago.
I was quite surprised to find that the following program will happily compile and run (using "cargo 1.42.0 (86334295e 2020-01-31)."), outputting:
5
k
The variable x which is not declared as mut is not only reassigned but reassigned with a different type.
Is there some reason why you are allowed to do this?
fn main() {
let x = 5;
println!("{}", x);
let t: (i32, f64, char) = (2, 3.14, 'k');
let (_,_,x) = t;
println!("{}", x);
}
This is called "shadowing a variable"
(https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing)
It can also been shown as simply as so:
let x = 5;
let x = 'k';
It actually comes in handy often. For instance, you can reuse an identifier after you are done using its initially assigned value:
let two_times_five = 2 * 5; // type i32
let two_times_five = two_times_five.to_string(); // type String
The compiler will still enforce strong typing; accesses to two_times_five before its redefinition will be accessing an i32, accesses afterward will be accessing a String.
There are also times when you don't want a variable to be mutable, but at some point you want to assign it a different value. Using variable shadowing rather than let mut means you know the variable is not changed in between its definitions, regardless of what functions it's passed into or methods are called on it.

How to let borrow checker know reference is no longer present? [duplicate]

This question already has answers here:
Borrow checker doesn't realize that `clear` drops reference to local variable
(6 answers)
What are the options to end a mutable borrow in Rust?
(1 answer)
Closed 3 years ago.
I have a problem with the borrow checker in the following scenario: First I store an immutable reference to a mutable variable x, which I later use elsewhere in my code. Now I come to a point where I want to change the value of x. Knowing that there is an immutable reference to it inside foo.bar, first I remove the reference by calling foo.bar.clear().
Now that there are no immutable borrows, I'd expect that I can mutate the object, but that's not case. I assume that the problem is that the compiler has no way of knowing that clear() drops the references inside foo.bar, but I'm clueless how to proceed in this situation.
Minimal example:
struct Foo<'a> {
bar: Vec<&'a i32>
}
fn main() {
let mut x = 42;
let mut foo = Foo { bar: vec![&x] };
// Do immutable stuff with foo.bar[0]... then:
foo.bar.clear();
x += 1;
foo.bar.push(&x);
println!("X is: {}", foo.bar[0]);
}
playground

Shadowing in without "let" [duplicate]

This question already has answers here:
Why do I need rebinding/shadowing when I can have mutable variable binding?
(2 answers)
Closed 4 years ago.
From my understanding, shadowing in Rust allows you to use the same variable by using let and re-declaring the variable e.g.
let x = 5;
let x = x + 1;
let x = x * 2;
println!("The value of x is: {}", x);
but, if you make the variable mutable, doesn't that mimic shadowing e.g.:
let mut x = 5;
println!("The value of x is: {}", x);
x = 6;
println!("The value of x is: {}", x);
x = 7;
println!("The value of x is: {}", x);
In example 1 & 2, where is the variable stored, in the stack or heap?
All values in your example are stored on the stack. In example 1, a new value is pushed onto the stack for each let statement.
It looks like you got the example from The Rust Programming Language. Maybe read this paragraph again for emphasis:
The other difference between mut and shadowing is that because we’re
effectively creating a new variable when we use the let keyword again,
we can change the type of the value but reuse the same name.

Rust mutable value vs mutable reference [duplicate]

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.

Resources