I am relatively new to Rust and wanted to learn it by building a game with Piston.
There I have a Renderer
struct that renders the scene and a main loop that handles game-logic events. They both need a mutable borrow and I understand that multiple borrows can lead to undefined behaviour, but I don't understand how it can in my case, since I always use the object in different scopes and in the same thread.
I had a look at this question and feel like I am supposed to use Rc
and/or RefCell
to solve this, but this seems too extreme. I also don't think I need ownership in the renderer (or do I, then why?), because the renderer lives shorter than the main loop.
Another solution would be to pass the mutable object every time it is needed, but in the real case this is almost for every function and I come from Java/C++ where the below code worked.
struct Renderer<'a> {
w: &'a mut Window,
}
impl<'a> Renderer<'a> {
fn render(&mut self) {
let w = &mut self.w;
// complex render operation needing the window mutably
}
}
struct Window {
//...
}
impl Window {
fn poll_event(&mut self) {
//some internal code of piston
}
}
fn main() {
let mut w = Window {};
let mut renderer = Renderer { w: &mut w };
loop {
{
//first event handling
w.poll_event();
}
{
//AFTERWARDS rendering
renderer.render();
}
}
}
With the error:
error[E0499]: cannot borrow `w` as mutable more than once at a time
--> src/main.rs:29:13
|
24 | let mut renderer = Renderer { w: &mut w };
| - first mutable borrow occurs here
...
29 | w.poll_event();
| ^ second mutable borrow occurs here
...
36 | }
| - first borrow ends here
My Rc
approach compiles fine, but seems over the top:
use std::rc::Rc;
struct Renderer {
w: Rc<Window>,
}
impl Renderer {
fn render(&mut self) {
let w = Rc::get_mut(&mut self.w).unwrap();
// complex render operation needing the window mutably
}
}
struct Window {
//...
}
impl Window {
fn poll_event(&mut self) {
//some internal code of piston
}
}
fn main() {
let mut w = Rc::new(Window {});
let mut renderer = Renderer { w: w.clone() };
loop {
{
//first event handling
Rc::get_mut(&mut w).unwrap().poll_event();
}
{
//AFTERWARDS rendering
renderer.render();
}
}
}
All I actually need to do is delaying the &mut
. This works with Rc
but I don't need ownership - so all the unwrap
stuff will never fail since I (can) use it in different scopes.
Can this predicament be resolved or am I forced to use Rc
in this case?
If there is a more "Rusty" way of doing this, please let me know.