helix_tp
helix_tp

Reputation: 13

i need to push (Vec) of a member of struct contained, he is a struct as well

I am trying to add a member of a structure that is itself a structure. I have the classic mistake "can not move out of borrowed content".

How can I get around the problem

thanks in advance.

use std::cell::RefCell;

pub struct Sprite {
    pub x: f32,
    pub y: f32,
}

impl Sprite {
    pub fn new(x: f32, y: f32) -> Sprite {
        let sprite: Sprite = Sprite { x: x, y: y };
        sprite
    }
}

pub struct Human {
    pub x: f32,
    pub y: f32,
    pub sprite: Sprite,
}

impl Human {
    pub fn new() -> Human {

        Human {
            x: 400.0,
            y: 300.0,
            sprite: Sprite::new(1.0, 1.0),
        }
    }
}

pub struct Game {
    pub human: Human,
    sprites: Vec<RefCell<Sprite>>,
}

impl Game {
    pub fn new() -> Game {
        let human = Human::new();

        Game {
            human: human,
            sprites: vec![],
        }
    }

    pub fn init(&mut self) {
        let  sprite  = self.human.sprite; //error : can not move out of borrowed content
        self.create_sprite(sprite);
    }

    fn create_sprite(&mut self, sprite: Sprite) {
        self.sprites.push(RefCell::new(sprite));
    }
}
fn main() {}

I made the change proposed by RLS, which only displaced the problem.

I also tried to change the "lifetime" with annotations, it did not work either, but maybe I am wrong. I do not know this feature well.

REM : The code is purge for shows the error and compiled

Upvotes: 1

Views: 107

Answers (1)

chargedPeptide
chargedPeptide

Reputation: 445

Right, so your:

let sprite = human.sprite 

Attempts to take ownership of the sprite field away from the human it is defined in. This is prohibited in rust since it would leave a dangling reference in the struct if the original reference is destroyed, or double references if copied. Both unsafe.
Using a borrow allows simpler code semantics but borrows are supposed to have a specific lifetime, i.e. in general not stick around since the thing you are borrowing from might outlive the borrow reference otherwise. The final option that's typically used is just copying the data, but since it seems you want to track the full state of your sprites from several places that wouldn't work here. Copying data would not leave a reference to the original.

There are ways around this in Rust. So, since it seems to me you want to be able to reference the same Sprite-struct from two locations you need a lot of wrapping here. I´ve added reference counting to your RefCell, this Rc wrapper can then be cloned and kept as a reference to the original Struct in several places. The RefCell then provides the actual read-write "lock" to allow the data to be mutated from several places.

Have a look below and see if this brings you closer to your usecase:

use std::rc::Rc;
use std::cell::RefCell;

pub struct Sprite {
    pub x: f32,
    pub y: f32,
}

impl Sprite {
    pub fn new(x: f32, y: f32) -> Sprite {
        let sprite: Sprite = Sprite { x: x, y: y };
        sprite
    }
}

pub struct Human {
    pub x: f32,
    pub y: f32,
    pub sprite: Rc<RefCell<Sprite>>,
}

impl Human {
    pub fn new() -> Human {

        Human {
            x: 400.0,
            y: 300.0,
            sprite: Rc::new(RefCell::new(Sprite::new(1.0, 1.0))),
        }
    }
}

pub struct Game {
    pub human: Human,
    sprites: Vec<Rc<RefCell<Sprite>>>,
}

impl Game {
    pub fn new() -> Game {
        let human = Human::new();

        Game {
            human: human,
            sprites: vec![],
        }
    }

    pub fn init(&mut self) {
        let  sprite  = self.human.sprite.clone(); //error : can not move out of borrowed content
        self.create_sprite(sprite);
    }

    fn create_sprite(&mut self, sprite: Rc<RefCell<Sprite>>) {
        self.sprites.push(sprite);
    }
}
fn main() {}

Upvotes: 2

Related Questions