Rc::降级似乎不会降低Rust程序的所有权



我试图在Rust中创建一个简单的扫雷器。为此,我想创建一个Grid对象,保存所有Case对象。单击Case,通知Grid

我希望所有的情况下有一个Weak对网格的引用。为什么借用检查器阻止我这样做?

引用文档:

WeakRc的一个版本,它持有对托管分配的非归属引用。

注释标记的link不应该拥有网格,但编译器告诉我该值已被移动。

use std::rc::{Rc, Weak};
pub struct Grid {
dimensions: (usize, usize),
n_mines: usize,
content: Vec<Vec<Case>>,
}
impl Grid {
pub fn new(dimensions: (usize, usize), n_mines: usize) -> Self {
let (n, m) = dimensions;
let mines: Vec<Vec<Case>> = Vec::with_capacity(m);
let mut grid = Self {
dimensions: dimensions,
n_mines: n_mines,
content: mines,
};
let link = Rc::new(grid);
let link = Rc::downgrade(&link); // here link loses the ownership of grid, right ?
println!("{}n", grid.n_mines);
for i in 0..m {
let mut line: Vec<Case> = Vec::with_capacity(n);
for j in 0..n {
let case = Case::new_with_parent((i, j), Weak::clone(&link));
line.push(case)
}
grid.content.push(line);
}
grid
}
pub fn click_neighbours(&mut self, coordinates: (usize, usize)) {
let surrouding = vec![(0, 0), (0, 1)]; // not a real implementation
for coord in surrouding {
self.content[coord.0][coord.1].click();
}
}
}
pub struct Case {
pub coordinates: (usize, usize),
parent: Weak<Grid>,
}
impl Case {
pub fn new_with_parent(coordinates: (usize, usize), parent: Weak<Grid>) -> Case {
Self {
coordinates: coordinates,
parent: parent,
}
}
pub fn click(&mut self) {
match self.parent.upgrade() {
Some(x) => x.click_neighbours(self.coordinates),
None => println!("whatever, not the issue here"),
}
}
}
fn main() {
let grid = Grid::new((10, 10), 5);
}

我通过将网格内容放入RefCell,在运行时尝试了多种变体来执行借用规则。我目前也在尝试在Rust中采用Observer设计模式实现来解决我的问题,但到目前为止还没有任何成功。

这里有一个误解,通过移动这里的网格:

let link = Rc::new(grid);

你不可挽回地摧毁了grid,但无论你对link做什么,都不能唤回原来的grid。唯一可以这样做的是使用Rc::try_unwrap来打开link并将其分配回grid,但这不是你想在这里做的。

你可以用RefCell来代替,像这样:

let grid = Rc::new(RefCell::new(grid));

然后让你编辑网格里面的borrow_mut:

grid.borrow_mut().content.push(line);

你可以在PitaJ的回答中看到你的代码的完整清单应该是什么样子的。

  1. grid被移到了Rc::new中,所以你不能再使用它了。你必须从Grid::new

    返回Rc
  2. 当你持有Weak对它的引用时,你不能修改Rc中的值。因此,您必须在RefCell中包装内部值。否则,创建lines的循环是不可能的

这是你的代码的有效版本:

use std::cell::RefCell;
use std::rc::{Rc, Weak};
pub struct Grid {
dimensions: (usize, usize),
n_mines: usize,
content: Vec<Vec<Case>>,
}
impl Grid {
pub fn new(dimensions: (usize, usize), n_mines: usize) -> Rc<RefCell<Self>> {
let (n, m) = dimensions;
let mines: Vec<Vec<Case>> = Vec::with_capacity(m);
let grid = Rc::new(RefCell::new(Self {
dimensions: dimensions,
n_mines: n_mines,
content: mines,
}));
let link_weak = Rc::downgrade(&grid);
println!("{}n", grid.borrow().n_mines);
{
// avoid repeatedly calling `borrow_mut` in the loop
let grid_mut = &mut *grid.borrow_mut();
for i in 0..m {
let mut line: Vec<Case> = Vec::with_capacity(n);
for j in 0..n {
let case = Case::new_with_parent((i, j), Weak::clone(&link_weak));
line.push(case)
}
grid_mut.content.push(line);
}
}
grid
}
pub fn click_neighbours(&mut self, coordinates: (usize, usize)) {
let surrouding = vec![(0, 0), (0, 1)]; // not a real implementation
for coord in surrouding {
self.content[coord.0][coord.1].click();
}
}
}
pub struct Case {
pub coordinates: (usize, usize),
parent: Weak<RefCell<Grid>>,
}
impl Case {
pub fn new_with_parent(coordinates: (usize, usize), parent: Weak<RefCell<Grid>>) -> Case {
Self {
coordinates: coordinates,
parent: parent,
}
}
pub fn click(&mut self) {
match self.parent.upgrade() {
Some(grid) => grid.borrow_mut().click_neighbours(self.coordinates),
None => println!("whatever, not the issue here"),
}
}
}
fn main() {
let grid = Grid::new((10, 10), 5);
}

游乐场

最新更新