I know this question may be silly, but seems the rust book does not cover this point.
As we know, below code does not compile because s1 is no longer available, the ownership of s1 was moved to s2.
let s1 = String::from("One");
let s2 = s1; // s1 moved here
println!("{}", s1);
Now let's see this code:
let s1 = String::from("One");
let s1 = String::from("Two"); // what happened to the former `s1`?
println!("{}", s1);
This code will compile and print Two, but I would like to know, what happened to the former s1?
Is it just go out of scope and dropped? Will the memory be freed?
The original s1 variable still exists, you just can't access it any more once it's been shadowed. It will be dropped at the end of the scope, I believe.
It's still two variables, each holding its own value, having its own scope, and own drop, etc. The way to think about it is that name of the variable totally doesn't matter. Rust tracks variables in its own way, separate from their name.
I have not go to this part yet, seems that you write a own drop function and overridden the default drop?
I only have limited experience about Java's System.gc(), and it's not guaranteed to run each time when a variable goes out of scope, so drop will always be called in Rust?
To add to @Cerber-Ursi's comment: Drop in Rust is more like the destructor in C++. It will always run at the exact point in your code where the object goes out of scope, except when you override it as @Cerber-Ursi pointed out.
This enables the code to be baked into your program at a known location at compile time instead of having to pause to let a GC run to figure out what can be freed, but it makes things a little more complicated around reference cycles and self-references.
Applying what is described in Rustonomicon, the pseudo de-sugared version of the example code might look like the following:
'a: {
let s1: String = String::from("One");
'b: {
let s1: String = String::from("Two");
'c: { // besides the main point, but new scope to where the ownership is passed
println!("{}", s1);
}
}
}
Putting two and two together, I suspect
... is effected using the different scope ids the compiler uses to enforce many of our beloved rules. So, the two s1 are distinct because they live in different scopes. This is more often going to be the case because with every let statement Rust creates a new scope (so, tracking variables effectively becomes tracking scope ids).
One benefit of the overwrite is to enforce an intent not to extend the lifetime of the first scope by inadvertently referencing that 'a:s1 memory again.