亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

將可變的自引用傳遞給擁有對象的方法

將可變的自引用傳遞給擁有對象的方法

Git
慕妹3146593 2019-12-06 15:51:21
以下是一個簡單的模擬,其中的場是一個矩形區域,其中有兩個彈跳的球。該Field結構具有一個update方法,該方法調用update每個球。用它們的update方法,球需要根據它們的速度運動。但是他們還需要相互回應,以及領域的界限。fn main() {    let mut field = Field::new(Vector2d { x: 100, y: 100 });    field.update();}#[derive(Copy, Clone)]struct Vector2d {    x: i32,    y: i32,}struct Ball {    radius: i32,    position: Vector2d,    velocity: Vector2d,}impl Ball {    fn new(radius: i32, position: Vector2d, velocity: Vector2d) -> Ball {        Ball {            radius: radius,            position: position,            velocity: velocity,        }    }    fn update(&mut self, field: &Field) {        // check collisions with walls        // and other objects    }}struct Field {    size: Vector2d,    balls: [Ball; 2],}impl Field {    fn new(size: Vector2d) -> Field {        let position_1 = Vector2d {            x: size.x / 3,            y: size.y / 3,        };        let velocity_1 = Vector2d { x: 1, y: 1 };        let position_2 = Vector2d {            x: size.x * 2 / 3,            y: size.y * 2 / 3,        };        let velocity_2 = Vector2d { x: -1, y: -1 };        let ball_1 = Ball::new(1, position_1, velocity_1);        let ball_2 = Ball::new(1, position_2, velocity_2);        Field {            size: size,            balls: [ball_1, ball_2],        }    }    fn update(&mut self) {        // this does not compile        self.balls[0].update(self);        self.balls[1].update(self);    }}如何獲得有關邊界和另一個球的信息,以獲取Ball結構的更新功能?中的這些行Field::update不會編譯:self.balls[0].update(self);self.balls[1].update(self);出現以下錯誤:error[E0502]: cannot borrow `*self` as immutable because `self.balls[..]` is also borrowed as mutable  --> src/main.rs:62:30   |62 |         self.balls[0].update(self);   |         -------------        ^^^^- mutable borrow ends here   |         |                    |   |         |                    immutable borrow occurs here   |         mutable borrow occurs here我了解,但是我不知道該如何解決。
查看完整描述

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

}


查看完整回答
反對 回復 2019-12-06
?
智慧大石

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)

    }

}


查看完整回答
反對 回復 2019-12-06
  • 2 回答
  • 0 關注
  • 459 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號