admin管理员组文章数量:1401491
I am making a game in Rust and have a few different trait GameModule
s 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 AppModule
s, 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 GameModule
s 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 AppModule
s, 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 badges2 Answers
Reset to default 0let'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:
You're consuming
self
, which doesn't work in methods likeupdate(&mut self)
where you still need self afterward.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
版权声明:本文标题:rust - What are the differences between these two borrowing cases? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744305252a2599779.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论