Reputation: 13
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
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