【发布时间】:2016-09-17 20:44:40
【问题描述】:
我正在尝试学习 Rust,正如你所想象的那样,借用检查器是我最大的对手。所以这是我的设置,它是游戏战舰的一种板条箱。该游戏基于Battlefield 结构,该结构由Cells 组成。一个Cell 可以引用一个Ship,而一个Ship 具有一个包含所有引用它的Cells 的向量,因此它是一个双向只读关系。
pub struct Battlefield<'a> {
cells: Vec<Vec<Cell<'a>>>,
}
#[derive(Debug, PartialEq)]
pub struct Cell<'a> {
ship: Option<&'a Ship<'a>>
}
#[derive(Debug, PartialEq)]
pub struct Ship<'a> {
length: usize,
cells: Vec<&'a Cell<'a>>,
}
我的问题是Battlefield的place_ship函数:
impl<'a> Battlefield<'a> {
pub fn place_ship(&mut self,
ship: &'a mut Ship,
x: usize,
y: usize,
orientation: Orientation)
-> PlaceResult {
// check ship placement in bounds
// check affected cells are free
// set cells' ship ref to ship
// add cell refs to ship's cells field
}
}
这对我来说很有意义,我认为这里没有所有权问题,但似乎我错了:
#[cfg(test)]
mod tests {
use super::{Battlefield, X, Y};
use super::Orientation::*;
use super::super::ship::Ship;
#[test]
fn assert_ship_placement_only_in_bounds() {
let mut ship = Ship::new(3);
let mut bf = Battlefield::new();
assert_eq!(Ok(()), bf.place_ship(&mut ship, 0, 0, Horizontal));
assert_eq!(Ok(()), bf.place_ship(&mut ship, 5, 5, Vertical));
}
}
src/battlefield.rs:166:47: 166:51 error: cannot borrow `ship` as mutable more than once at a time [E0499]
src/battlefield.rs:166 assert_eq!(Ok(()), bf.place_ship(&mut ship, 5, 5, Vertical));
^~~~
src/battlefield.rs:165:47: 165:51 note: first mutable borrow occurs here
src/battlefield.rs:165 assert_eq!(Ok(()), bf.place_ship(&mut ship, 0, 0, Horizontal));
^~~~
我知道这只是一个简短的摘录,但整个代码太多了,无法在此处发布。 project can be found here(带有“货物构建”的标准构建)。
【问题讨论】:
-
但整个代码太多了,无法在此处发布 — 我保证您可以使代码足够小,以便在此处发布,同时仍能重现同样的错误。见minimal reproducible example。
-
可能是stackoverflow.com/q/32300132/155423的副本;也许stackoverflow.com/q/20698384/155423 或stackoverflow.com/q/28833622/155423 或stackoverflow.com/q/29893978/155423。或任何关于可变别名的问题。 Like the error says,您不能一次多次借用 anything 作为 mutable。
-
“双向” - “我不认为存在所有权问题” - 一旦建立了双向关系,所有权问题就会出现。
-
@SebastianRedl 为什么感谢您的建设性评论。幸好你记得在你的报价中保留“只读”......!在 rust 方面我可能是个菜鸟,但非 mut ref 与所有权无关。
-
@Leopard2A5 引用,mut 或 non-mut,以完全相同的方式影响所有权:所有者必须保持对象处于活动状态,直到引用消失。 mut 或 non-mut 只会影响可能采用的其他引用。是的,由于别名问题,mut 引用使双向关系更加困难,但 Rust 使任何类型的双向关系变得困难。看看实现一个双向链表是多么棘手。底线是,在 Rust 中,重新设计通常是最好的选择,直到双向关系消失。
标签: rust borrow-checker