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.
Related
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.
This question already has an answer here:
Why Rust allows declaring same variable name twice in a scope? [duplicate]
(1 answer)
Closed 1 year ago.
Hello fellow Rustaceans!
How it is possible that i can write that in Rust:
let mut v : Vec<u8> = Vec::new();
v.push(0);
v.push(1);
v.push(2);
let s = &v;
print!("{:?} - ", s); // will output "[0, 1, 2]"
let s = &v[1..];
println!("{:?}", s); // will screen "[1, 2]"
Normaly variables are immutable by default, no ?
And here i can change the value of the slice (s)
but normaly s is declared than variable with "let" ?
what's wrong ?
As pointed out in the comments, you're making a new variable called s. Up to renaming, your code is equivalent to
let mut v : Vec<u8> = Vec::new();
v.push(0);
v.push(1);
v.push(2);
let s = &v;
print!("{:?} - ", s); // will output "[0, 1, 2]"
let my_unrelated_s_variable = &v[1..];
println!("{:?}", my_unrelated_s_variable); // will screen "[1, 2]"
The two s you declared are, as far as the Rust compiler is concerned, unrelated variables. In fact, we could even give the second one a different type.
let s = &v;
let s = 42; // This one's an integer, but it's fine
This sort of shadowing is very common in Rust when we want to augment a particular value but want to respect immutability, as it guarantees we aren't actually changing anything in memory while allowing us the convenience of reusing variable names. For example, I often find myself doing things like this.
fn example(input: &str) {
let input = some_complicated_parsing_step(input)?;
...
}
The argument input is a string, and I want to convert it to something (maybe parse it as JSON, maybe read an integer from it, etc.). Once I do that, I have no use for the original string anymore, and it's reasonable to call the result of parsing input, as it is still the input I was given, just in a different form now.
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.
I have the following Rust program and I expect it to result in an compilation error since x is reassigned later. But it complies and gives output. Why?
fn main() {
let (x, y) = (1, 3);
println!("X is {} and Y is {}", x, y);
let x: i32 = 565;
println!("Now X is {}", x);
}
Rust actually lets you shadow other variables in a block, so let x: i32 = 565; is defining a new variable x that shadows the x defined earlier with let (x,y) = (1,3);. Note that you could even have redefined x to have a different type since the second x is a whole new variable!
fn main(){
let x = 1;
println!("Now X is {}",x);
let x = "hi";
println!("Now X is {}",x);
}
This reddit thread goes into more detail about why this is useful. The two things that are mentioned that seem interesting are:
For operations which take ownership of the variable, but return another variable of the same type, it sometimes "looks nice" to redefine the returned variable to have the same name. From here:
let iter = vec.into_iter();
let iter = modify(iter);
let iter = double(iter);
Or to make a variable immutable:
let mut x;
// Code where `x` is mutable
let x = x;
// Code where `x` is immutable
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.