我有一个小游戏应用程序,使用特征对象来处理关键事件并修改应用程序状态:
pub trait GameScene {
fn handle_key_events(&self, app: &mut TypingApp, key_event: KeyEvent) -> Result<()>;
}
pub struct StartupScene {}
impl GameScene for StartupScene {
fn handle_key_events(&self, app: &mut TypingApp, key_event: KeyEvent) -> Result<()> {
todo!()
}
}
pub struct TypingApp {
/// lots of other members here
/// ......
/// modify above members according to the user's input
pub cur_scene: Box<dyn GameScene>
}
impl Default for TypingApp {
fn default() -> Self {
Self {
cur_scene: Box::new(StartupScene{})
}
}
}
impl TypingApp {
pub fn handle_key_events(&mut self, key_event: KeyEvent) -> Result<()> {
self.cur_scene.handle_key_events(self, key_event)
}
}
这无法编译,因为最后一个handle_key_events
函数:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/app.rs:53:9
|
53 | self.cur_scene.handle_key_events(self, key_event)
| --------------^-----------------^^^^^^^^^^^^^^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
| immutable borrow occurs here
我只想使用GameScene
对象来修改的成员TypingApp
,我该如何修复这个编译错误?谢谢!
这种情况与这个问题描述的情况类似,答案可以在这里应用。
问题在于,在最后一个函数调用中,
self.cur_scene
被引用(&self
特征函数的参数),而包含此成员的结构由下一个参数( )独占app: &mut TypingApp
访问。这意味着,在特征函数的实现中,有可能cur_scene
直接通过self
参数访问成员,并通过app
参数作为独占引用间接访问成员。当然,Rust 阻止我们这样做。解决这个问题的想法是使用
Option
(即使我们不认为该成员是可选的)来使同时共享+独占访问变得不可能,通过在调用期间暂时从其包含结构中删除该成员并在之后将其放回。在
TypingApp
结构中在初始化过程中
在实施过程中
有很多方法可以解决这个问题,我将概述我考虑的两种方法。你遇到的主要问题是你试图同时可变地借用整个结构和它的一个字段,而 Rust 不允许这样做。一个简单的解决方法是将
handle_key_events
可能需要接触的所有状态放入其自己的结构中:然后你需要改变特征方法定义来
&mut AppState
对整个应用程序进行操作:并改变呼叫站点:
现在您正在借用两个不相交的字段,这是允许的。
另一种更彻底的方法改变是转向一种更具声明性的风格,这种风格
handle_key_events
不会修改任何内容,而是生成TypingApp
自己处理的消息: