2
#[derive(Debug)]
struct MyStruct {
    a: u32,
    b: String,
}

fn main() {
    let mut s;
    {
        let _s = MyStruct {
            a: 1,
            b: "hello".to_string(),
        };
        //s = &_s;   // Error
        s = _s;      // Not an error
    }
    println!("{:?}", s);
}

The commented line is an error since the variable s would be a dangling pointer. However, I don't understand why s = _s; is not an error.

_s is created on the stack and dropped before the println macro is called. I didn't specify the Copy bound for MyStruct. I'm confused whether the variable s is pointing to the dangling pointer or copied from _s. The former can't be true since the compiler error didn't appear and the latter case is not understandable because I didn't implement Copy for MyStruct.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Hyunsoo
  • 139
  • 1
  • 10
  • 3
    *and dropped before the `println` macro is called* — it is not. It is moved. I encourage you to re-read [What Is Ownership?](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html?) – Shepmaster Feb 22 '22 at 15:34
  • 1
    See also [What does 'let x = x' do in Rust?](https://stackoverflow.com/q/54595345/155423) – Shepmaster Feb 22 '22 at 15:38

1 Answers1

2

I think it is clear to you why &_s can't be used when the scope _s is defined leaved. Your question is why the other works.

In Rust, if a type implements the Copy trait, a statement like a=b will do a bitwise copy of b that will be accessible by a. After that, there will be two copies of the same object. If it is not a Copy type, then it will be moved into a. However, it is not necessarily a memory move operation taking place under the hood as it may stay in the same place in the stack, but this is not relevant to understand this question.

After the move, the object is bound to the new variable s, and the scope that s is defined is relevant from then on.

Note: You don't need s to be mutable for this because the s = _s; line is not an assignment but initialization.

  • Thank you for the clear explanation. I got your point. The ownership seems does not to care about the location of the created variable because the struct variable is created in the inner scope and still alive in the outer scope. Is it correct? – Hyunsoo Feb 22 '22 at 15:49
  • Yes exactly. It may be returned from a function, but it is the same. – Özgür Murat Sağdıçoğlu Feb 22 '22 at 15:53
  • 1
    _"in fact nothing is moved"_ → not quite: in this specific case, nothing is actually moved but in some situations the value may move in memory (i.e. its address may change). What matters is that only one memory location is valid at the same time, so once the value is "moved" (whether it changed location or not) the original is no longer valid. – Jmb Feb 22 '22 at 16:07
  • @Jmb yes you are right, thank you. As an example, if there is a conditional in the `foo`, there may be more than one candidate to return, and the actual returned value will be copied in to final destination. I have removed that sentence. – Özgür Murat Sağdıçoğlu Feb 22 '22 at 16:23
  • For ilustration purposes: If you try to access `_s` after you assign it to `s`, you would get a compilation error that `_s` was moved. – mhutter Feb 23 '22 at 00:40