Вместо присвоения p
заимствованной ссылки необходимо клонировать Rc
:
use std::cell::RefCell;
use std::rc::Rc;
struct Node {
val: i32,
next: Option<Rc<RefCell<Node>>>,
}
fn iterate(node: Option<Rc<RefCell<Node>>>) -> Vec<i32> {
let mut p = node;
let mut result = vec![];
loop {
let node = match p {
None => break,
Some(ref n) => Rc::clone(n), // Clone the Rc
};
result.push(node.as_ref().borrow().val); //works because val is Copy
p = match node.borrow().next {
None => None,
Some(ref next) => Some(Rc::clone(next)), //clone the Rc
};
}
result
}
fn main() {
let node = Some(Rc::new(RefCell::new(Node {
val: 0,
next: Some(Rc::new(RefCell::new(Node { val: 1, next: None }))),
})));
let result = iterate(node);
print!("{:?}", result)
}
Это необходимо, потому что вы пытаетесь использовать переменную с более коротким сроком службы в контексте, который требует более длительного срока службы. Результат p.as_ref().unwrap().borrow()
удаляется (т.е. освобождается, выделяется) после итерации цикла, но вы пытаетесь использовать его члены в следующем цикле (это называется use after free
, и одна из целей разработки Rust состоит в том, чтобы предотвратить это).
Проблема в том, что займы не являются собственностью объекта. Если вы хотите использовать next
в качестве p
в следующем цикле, тогда p
должен будет владеть объектом. Это может быть достигнуто с помощью Rc
(т. Е. 'Подсчитано ссылок') и позволяет использовать несколько владельцев в одном потоке.
Что если определение Node::next
равно Option<Box<RefCell<Node>>>
, как перебрать этот список?
Да, я также очень запутался с RefCell
, без RefCell
мы можем перебирать список, используя только ссылку, но потерпим неудачу с RefCell
. Я даже пытался добавить вектор Ref
, чтобы сохранить ссылку, но все равно не удалось.
Если вы уроните RefCell
, вы можете повторить его так:
struct Node {
val: i32,
next: Option<Box<Node>>,
}
fn iterate(node: Option<Box<Node>>) -> Vec<i32> {
let mut result = vec![];
let mut next = node.as_ref().map(|n| &**n);
while let Some(n) = next.take() {
result.push(n.val);
let x = n.next.as_ref().map(|n| &**n);
next = x;
}
result
}
fn main() {
let node = Some(Box::new(Node {
val: 0,
next: Some(Box::new(Node { val: 1, next: None })),
}));
let result = iterate(node);
print!("{:?}", result)
}
Возможно, это возможно и с RefCell
, но я не смог обойти проблемы с жизненным циклом.