Assignment to dereferenced self - what does it doo?

Viewed 133

I'm new to rust and hope you can explain what will happen if you assign to dereferenced self?

Does it change value in memory by the same reference, or it will destroy value in memory and create new with new reference?

struct X {
    v: f32,
}
impl X {
    fn new() -> X {
        X {
            v: 0.0,
        }
    }

    fn do_it(&mut self) {
            *self = X::new();
        }
    }
}

I'm learning rust by following game creation tutorial and in it if player starts a new game i need to revert GameState to default.

impl GS {
    fn new() -> GS {
        GS {
            frame_time: 0.0,
            player: Player::new(),
            obstacle: Obstacle::new(),
            interface_state: InterfaceState::MainMenu,
        }
    }

    fn main_menu(&mut self, ctx: &mut BTerm) {
        ctx.cls();
        ctx.print_centered(WINDOW_HEIGHT / 2 - 5, "Menu");
        ctx.print_centered(WINDOW_HEIGHT / 2 - 4, "New Game - Q");

        if Some(VirtualKeyCode::Q) == ctx.key {
            *self = GS::new();
            self.interface_state = InterfaceState::Playing;
        }
    }
}
2 Answers

or it will destroy value in memory and create new with new reference?

This one, kinda.

At its core, a reference is a pointer (just one that the typesystem understand and can check things about, also one that's never null).

So when you deref-assign to a reference you're replacing the pointee with whatever you're providing, and if necessary the old pointee is Dropped.

I'm not sure what distinction you make between "changing value in memory" and "destroying value in memory and creating new". I'd say it does a bit of both:

  • If your struct implements Drop, or if it contains fields that implement Drop, then assigning to *self will call all the drop methods.
  • Then it reinitializes the contents of self.

In the end, the value of self in memory is replaced with a clean value:

#[derive (Debug)]
struct Foo {
   x: i32,
}

impl Foo {
   fn new() -> Foo { Foo { x: 0 } }

   fn reset (&mut self) {
      *self = Foo::new();
   }
}

impl Drop for Foo {
    fn drop (&mut self) {
        println!("Dropping {:?}", self);
    }
}


fn main() {
    let mut f = Foo::new();
    println!("Initial: {:?}", f);
    f.x = 42;
    println!("Modified: {:?}", f);
    f.reset();
    println!("After reset: {:?}", f);
}

Playground

prints:

Initial: Foo { x: 0 }
Modified: Foo { x: 42 }
Dropping Foo { x: 42 }
After reset: Foo { x: 0 }
Dropping Foo { x: 0 }
Related