2 回答

TA貢獻1864條經驗 獲得超6個贊
當前,您的Ball結構需要了解Field它所包含的內容,以便能夠自我更新。這不會編譯,因為結果將是循環引用與變異結合在一起。您可以通過使用Cell或RefCell(后者會降低性能)來完成這項工作,但最好以不同的方式構造代碼。讓該Field結構檢查并解決Ball- Ball和Ball- Wall沖突。該Ball結構的update函數可以處理更新Ball的位置。
// Ball's update function
fn update(&mut self) {
// update position
}
// Field's update function
fn update(&mut self) {
for ball in self.balls.iter_mut() {
ball.update();
}
// check for collisions
// resolve any collisions
}

TA貢獻1946條經驗 獲得超3個贊
這是一個較小的示例:
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: &Field) {}
}
struct Field {
ball: Ball,
}
impl Field {
fn update(&mut self) {
self.ball.update(self)
}
}
問題
當您傳遞對的引用時Field,您將保證Field不能更改(“不可變引用” 的不可變部分)。但是,此代碼也試圖改變它的一部分:球!self或field在實施中應參考哪個參考Ball::update?
解決方案:僅使用您需要的字段
您可以將結構所需的部分與不需要的部分分開,update并在調用update函數之前使用它們:
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: &u8) {}
}
struct Field {
players: u8,
ball: Ball,
}
impl Field {
fn update(&mut self) {
self.ball.update(&self.players)
}
}
您甚至可以將這些零星的引用捆綁到一個整齊的包中:
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: BallUpdateInfo) {}
}
struct BallUpdateInfo<'a> {
players: &'a u8,
}
struct Field {
players: u8,
ball: Ball,
}
impl Field {
fn update(&mut self) {
let info = BallUpdateInfo { players: &self.players };
self.ball.update(info)
}
}
或重組您的包含結構以將信息與開頭分開:
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: &UpdateInfo) {}
}
struct UpdateInfo {
players: u8,
}
struct Field {
update_info: UpdateInfo,
ball: Ball,
}
impl Field {
fn update(&mut self) {
self.ball.update(&self.update_info)
}
}
解決方案:從中刪除成員 self
您也可以采用其他方法,Ball從中進行刪除,Field然后再對其進行任何更改。如果您可以輕松/廉價地制造Ball,請嘗試更換它:
use std::mem;
#[derive(Default)]
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: &Field) {}
}
struct Field {
ball: Ball,
}
impl Field {
fn update(&mut self) {
let mut ball = mem::replace(&mut self.ball, Ball::default());
ball.update(self);
self.ball = ball;
}
}
如果您不容易創建新值,則可以使用Optionand take:
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: &Field) {}
}
struct Field {
ball: Option<Ball>,
}
impl Field {
fn update(&mut self) {
if let Some(mut ball) = self.ball.take() {
ball.update(self);
self.ball = Some(ball);
}
}
}
解決方案:運行時檢查
您可以通過以下方式將借閱檢查移至運行時而不是編譯時RefCell:
use std::cell::RefCell;
struct Ball {
size: u8,
}
impl Ball {
fn update(&mut self, field: &Field) {}
}
struct Field {
ball: RefCell<Ball>,
}
impl Field {
fn update(&mut self) {
self.ball.borrow_mut().update(self)
}
}
- 2 回答
- 0 關注
- 459 瀏覽
添加回答
舉報