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 关注
- 418 浏览
添加回答
举报