admin管理员组

文章数量:1401491

I am making a game in Rust and have a few different trait GameModules that are a part of the main App.

pub struct AppView<'a> {
    pub frame_delta: &'a f64, 
    pub area: &'a Rect
}
pub trait GameModule: WidgetRef {
    /// Update the AppComponent before each render.
    /// 
    /// Exits app on `Ok(false)` or `Err(_)`.
    fn update(&mut self, world: Rc<RefCell<World>>, app_view: &AppView) -> Result<bool>;
    /// Handle key events.
    /// 
    /// Exits app on `Ok(false)` or `Err(_)`.
    fn key_event(&mut self, world: Rc<RefCell<World>>, app_view: &AppView, key_event: KeyEvent) -> Result<bool>;
    /// Handle mouse events.    /// 
    /// Exits app on `Ok(false)` or `Err(_)`.
    fn mouse_event(&mut self, world: Rc<RefCell<World>>, app_view: &AppView, mouse_event: MouseEvent) -> Result<bool>;
}

I have a main controller that is an GameModule and has a list of AppModules, called TabWidget that updates the correct GameModule. I have an update(&mut self) -> Result<bool> function in pub struct App that has

pub fn update(&mut self) -> Result<bool> {
    let app_view = AppView {
        area: &self.tab_area,
        frame_delta: &self.frame_delta,
    };
    self.tab_widget.update(self.world.clone(), &app_view)
}

This code above works, but I attempted, first to write a function:

pub fn app_view(&self) -> AppView {
    AppView {
        frame_time: &self.frame_time,
        area: &self.tab_area
    }
}

When I used this function in App::update(&mut self) -> Result<bool>, suddenly I encountered a borrowing error.

pub fn update(&mut self) -> Result<bool> {
    let app_view = self.app_view();
    self.tab_widget.update(self.world.clone(), &app_view)
}

and

pub fn update(&mut self) -> Result<bool> {
    self.tab_widget.update(self.world.clone(), &self.app_view)
}

both refused to compile. I think I understand that Rust here is implicitly borrowing self, but App is 'static, and this implementation is for App<'static>, so when I tried:

pub fn app_view(self) -> AppView {
    // ...
}

it required that AppView be assigned the static lifetime which didn't seem like it would make sense.

What are the workarounds here? Am I misunderstanding Rust? Why does one work and the other doesn't?

As it turns out, what I am attempting here falls under RFC #1215 but in my case can be simplified by allowing AppView to be constructed from copies of the data passed in, not references. And in the case that later I do require them to be references, for heavier loads, my semantics allow me to just create one AppView and re-use it for all the functions called in that frame.

I am making a game in Rust and have a few different trait GameModules that are a part of the main App.

pub struct AppView<'a> {
    pub frame_delta: &'a f64, 
    pub area: &'a Rect
}
pub trait GameModule: WidgetRef {
    /// Update the AppComponent before each render.
    /// 
    /// Exits app on `Ok(false)` or `Err(_)`.
    fn update(&mut self, world: Rc<RefCell<World>>, app_view: &AppView) -> Result<bool>;
    /// Handle key events.
    /// 
    /// Exits app on `Ok(false)` or `Err(_)`.
    fn key_event(&mut self, world: Rc<RefCell<World>>, app_view: &AppView, key_event: KeyEvent) -> Result<bool>;
    /// Handle mouse events.    /// 
    /// Exits app on `Ok(false)` or `Err(_)`.
    fn mouse_event(&mut self, world: Rc<RefCell<World>>, app_view: &AppView, mouse_event: MouseEvent) -> Result<bool>;
}

I have a main controller that is an GameModule and has a list of AppModules, called TabWidget that updates the correct GameModule. I have an update(&mut self) -> Result<bool> function in pub struct App that has

pub fn update(&mut self) -> Result<bool> {
    let app_view = AppView {
        area: &self.tab_area,
        frame_delta: &self.frame_delta,
    };
    self.tab_widget.update(self.world.clone(), &app_view)
}

This code above works, but I attempted, first to write a function:

pub fn app_view(&self) -> AppView {
    AppView {
        frame_time: &self.frame_time,
        area: &self.tab_area
    }
}

When I used this function in App::update(&mut self) -> Result<bool>, suddenly I encountered a borrowing error.

pub fn update(&mut self) -> Result<bool> {
    let app_view = self.app_view();
    self.tab_widget.update(self.world.clone(), &app_view)
}

and

pub fn update(&mut self) -> Result<bool> {
    self.tab_widget.update(self.world.clone(), &self.app_view)
}

both refused to compile. I think I understand that Rust here is implicitly borrowing self, but App is 'static, and this implementation is for App<'static>, so when I tried:

pub fn app_view(self) -> AppView {
    // ...
}

it required that AppView be assigned the static lifetime which didn't seem like it would make sense.

What are the workarounds here? Am I misunderstanding Rust? Why does one work and the other doesn't?

As it turns out, what I am attempting here falls under RFC #1215 but in my case can be simplified by allowing AppView to be constructed from copies of the data passed in, not references. And in the case that later I do require them to be references, for heavier loads, my semantics allow me to just create one AppView and re-use it for all the functions called in that frame.

Share Improve this question edited Mar 23 at 3:42 John Kugelman 362k69 gold badges552 silver badges596 bronze badges asked Mar 22 at 20:01 sackboysackboy 134 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

let's try to replicate it, see rust playground replica

fn update(&mut self) -> Result<bool, String>
{
    let app_view = self.app_view();
    self.tab_widget.update(self.world.clone(), &app_view);
    Ok(true)
}
error[E0502]: cannot borrow `self.tab_widget` as mutable because it is also borrowed as immutable
  --> src\main.rs
   |
79 |         let app_view = self.app_view();
   |                        ---- immutable borrow occurs here
80 |         self.tab_widget.update(self.world.clone(), &app_view);
   |         ^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |         |               |
   |         |               immutable borrow later used by call
   |         mutable borrow occurs here

the error is clear, self.app_view() borrows self completely in app_view, therefore self.tab_widget.update cannot borrow the other part (self.tab_widget) mutably. and you cannot make a function that only borrows a part of a struct, this is a current limitation in rust, see How can multiple parts of self be borrowed here? Isn't self borrowed mutably as well as immutably here?

AppView is only holding a float and a rectangle that's 2 more floats at most, it can cheaply copy them, it doesn't need to hold references and therefore borrow App, now the code should compile.

pub struct AppView {
    pub frame_delta: f64,
    pub area: Rect
}

another way is to construct AppView inside update, you are allowed to borrow multiple parts of a struct, you just need all those borrows to be in the same function.

fn update(&mut self) -> Result<bool, String> {
    let app_view = AppView{
        frame_delta: &self.frame_time,
        area: &self.tab_area,
    };
    self.tab_widget.update(self.world.clone(), &app_view);
    Ok(true)
}
pub fn update(&mut self) -> Result<bool> {
    let app_view = AppView {
        area: &self.tab_area,
        frame_delta: &self.frame_delta,
    };
    self.tab_widget.update(self.world.clone(), &app_view)
}

This works because you are explicitly creating a temporary borrow to self.frame_delta and self.tab_area before calling self.tab_widget.update(...), which also needs &mut self. The borrow ends at the end of the statement.

pub fn update(&mut self) -> Result<bool> {
    let app_view = self.app_view();
    self.tab_widget.update(self.world.clone(), &app_view)
}

or

self.tab_widget.update(self.world.clone(), &self.app_view())

These don't work because you're trying to call self.app_view(), which borrows self immutably, while the next method update(...) needs &mut self, and both borrows overlap across the same method call.

This won't compile either:


pub fn app_view(self) -> AppView { ... }

because:

  1. You're consuming self, which doesn't work in methods like update(&mut self) where you still need self afterward.

  2. Even if you make it app_view(self: &Self), the issue still persists because the borrow checker is not smart enough to split up the borrows cleanly in this context.

本文标签: rustWhat are the differences between these two borrowing casesStack Overflow