Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
There are two things going on here. One which technically explains what's going on fully, and another potential misconception you have. For the former, &T implements the Copy trait regardless ...
Answer
#1: Initial revision
There are two things going on here. One which technically explains what's going on fully, and another potential misconception you have. For the former, `&T` implements the `Copy` trait regardless of what `T` is. So all that's happening is when `r = inner;` executes it just does a bitwise copy of the *reference* which `inner` is over `r`. It's no different than if `r` and `inner` had been declared as `i64` say. Indeed, you can verify that a move didn't happen by adding code that uses `inner` after the `r = inner;` line. `inner` (trivially) owned a reference to a `str` but it never owned the `str` itself. The potential misconception is occurrences of string literals don't mean to dynamically allocate (either on the heap or the stack) a string, and then return a reference to it. Instead, the compiler will statically allocate space for the string literal and all occurrences of the string literal will be replaced with references to this statically allocated memory whose lifetime is the whole program. Formally, this is represented by the `'static` lifetime which subsumes, i.e. outlives, all other lifetimes. Incidentally, there is some terminological complexity here. The reference that `inner` is bound to has a lifetime which, in this example, is the scope containing `inner`. Reference types also contain a lifetime, the `'a` in `&'a T`, and that is how long the reference type requires the referred to data to live. Finally, the actual lifetime of the referred to data can be any lifetime which subsumes the lifetime the reference requires, i.e. a `&'a T` reference can refer to data that has a lifetime of `'b` as long as `'a : 'b`, i.e. `'b` contains `'a`. In summary, `inner` is a short-lived reference to immortal data. `s` and `r` are slightly longer-lived references to immortal data. `r = inner;` is just a bitwise copy of a pointer, and this is safe because the referred to data, being immortal will outlive any lifetime the reference type requires, i.e. `'a : 'static` for all `'a`. Playing with the following type can help illustrate what's happening. ```rust #[derive(Debug)] struct NoisyDrop { i: i64 } impl Drop for NoisyDrop { fn drop(&mut self) { println!("Dropping {}", self.i) } } ``` Since `NoisyDrop` does not implement the `Copy` trait, no implicit copying will happen. This first example illustrates what you were expecting, except now that we *are* locally allocating data, it behaves as you expect. ```rust let s = &NoisyDrop { i: 1 }; let mut r = s; println!("First ref is {:?}", r); { let inner = &NoisyDrop { i: 2 }; r = inner; } println!("Second ref is {:?}", r); ``` This will fail to compile since `NoisyDrop { i: 2 }` doesn't live as long as `r`'s type requires. However, what is actually happening in your example is more like: ```rust let s = &NoisyDrop { i: 1 }; let t = &NoisyDrop { i: 2 }; let mut r = s; println!("First ref is {:?}", r); { let inner = t; r = inner; } println!("Second ref is {:?}", r); ``` which is unproblematic. Not directly related to your question, but you may find the output of this final example interesting: ```rust let s = NoisyDrop { i: 1 }; let mut r = s; println!("First ref is {:?}", r); { let inner = NoisyDrop { i: 2 }; println!("Before assign"); r = inner; println!("After assign"); } println!("Second ref is {:?}", r); ``` Here we're actually performing moves of the underlying data which changes who's responsible for calling `drop` on the data. This allows data to outlive the scope in which it is allocated. Note that in this example, unlike the others, `inner` is no longer usable after `r = inner;`.