Since the question of where a value is being destructed in Rust is relevant, there are consistent rules about the “drop scopes” of temporary variables. These have the effect that in the first code, the temporary value containing the result of i.to_string()
is dropped at the end of the let result = …;
statement.
These rules can be particularly relevant for things such as guard objects from Mutex
or RefCell
. If you write
let n: u32 = *my_mutex.lock().unwrap();
your code may be relying on the behavior that the RAII guard that resulted from the lock()
function is dropped at the end of the let
statement, so that subsequent code can e.g. re-lock it without dead-lock.
So there are not necessarily any good rules to “parse” the first code as the second, whilst not making other cases worse. Any changing the rules for temporary scopes/lifetimes would be a breaking change anyways; whilst perhaps possible with editions, for such a change, one would need even more convincing reasony.
One might wonder, whether there isn’t a solution without changing any existing code’s behavior. After all, the original code doesn’t compile so maybe just change it for code that would otherwise fail to compile?
However, at least if the idea would be to extend temporary lifetimes for code that would otherwise fail the borrow-checker is not necessarily a good ides. Rust is currently designed in a way that the borrow-checker, which is a complex beast that no Rust user will usually have an entirely complete and accurate mental model of anyways, does not ever influence program behavior. Instead it just aids as a verification tool whose only effect is that a program’s compilation can fail.
This approach has at least 2 great advantages: On one hand, an alternative Rust compiler may decide, to save a lot of work decide to (whilst of course then not being exactly safe to use) skip on implementing the borrow checker. (E.g. see this example.) Another advantage is that Rust may improve its borrow checker in the future. The borrow checker can become smarter, allowing more programs to be correctly identified as being memory safe. If there was program behavior dependent on whether or not the borrow-checker rejects another version of the program, then such improvements would be breaking changes; whereas with the borrow-checker not influencing program behavior, compiler developers can improve Rust’s borrow checker as a completely backwards-compatible affair. One effort on improving the current borrow checker in the future can be found here. Improvements in the past also exists, most notably so-called “non-lexical lifetimes” (NLL).
Edit: And a 3rd advantage, that I’ve already hinted at implicitly: It frees the programmer from understanding all the intricacies and corner cases of borrow checking just in order to figure out what their program is doing.