【发布时间】:2022-11-26 20:07:23
【问题描述】:
我想为有向无环图实现 Kahn 算法。
我理解为什么在 Rust 中不可能多次借用可变变量,而且如果可变变量已经借用为不可变变量,我也不能借用它,但我不想使用引用计数指针,因为它在堆上分配内存。
struct Node {
ref_count: u32,
id: usize,
text: String
}
impl Node {
fn new(text: String) -> Self {
Node {
ref_count: 0,
id: 0,
text: text
}
}
fn get_ref_count(&self) -> u32 {
self.ref_count
}
fn get_id(&self) -> usize {
self.id
}
fn execute(&self) {
println!("{}", self.text);
}
}
struct Edge {
from: usize,
to: usize
}
impl Edge {
fn new(from: &Node, to: &Node) -> Self {
Edge {
from: from.get_id(),
to: to.get_id()
}
}
}
struct Dag {
nodes: Vec<Node>,
edges: Vec<Edge>
}
impl Dag {
fn new() -> Self {
Dag {
nodes: vec![],
edges: vec![]
}
}
fn add_node(&mut self, node: Node) {
let id = self.nodes.len();
self.nodes.push(node);
self.nodes[id].id = id;
}
fn add_edge(&mut self, edge: Edge) {
self.edges.push(edge);
}
fn sort_and_execute(&mut self) {
for edge in &self.edges {
let node = &mut self.nodes[edge.to];
node.ref_count+=1;
}
let mut stack: Vec<&Node> = vec![];
for node in &self.nodes {
if node.get_ref_count() == 0 {
stack.push(node);
}
}
while !stack.is_empty() {
let node = stack.pop();
if let Some(node) = node {
node.execute();
let edges: Vec<&Edge> = self.edges
.iter()
.filter(|edge| edge.from == node.get_id() )
.collect();
for edge in edges {
//linked node must be mutable, because the ref count has to be decremented
let linkedNode = &mut self.nodes[edge.to];
linkedNode.ref_count -= 1;
if linkedNode.get_ref_count() == 0 {
stack.push(linkedNode);
}
}
}
}
}
}
fn main() {
let a = Node::new("0".to_owned());
let b = Node::new("1".to_owned());
let c = Node::new("2".to_owned());
let d = Node::new("3".to_owned());
let a_c = Edge::new(&a, &c);
let b_c = Edge::new(&b, &c);
let c_d = Edge::new(&c, &d);
let mut dag = Dag::new();
dag.add_node(a);
dag.add_node(b);
dag.add_node(c);
dag.add_node(d);
dag.add_edge(a_c);
dag.add_edge(b_c);
dag.add_edge(c_d);
dag.sort_and_execute();
}
问题是在73行中,for循环借用self.nodes来查找带有ref_count = 0的节点,在89行中,self.nodes也必须借用(可变地)以减少引用计数
有什么办法可以做到吗?
【问题讨论】:
-
请注意,
Vec也在堆上分配内存。话虽这么说,你可以使用RefCell,它使用你放置它的任何地方的内存(例如,堆栈用于局部变量,堆用于Box<RefCell<_>>,直接在数组中用于数组或Vec<RefCell<_>>)。 -
是的,
Vec也在堆上分配了内存,这是正确的,但是要处理这个算法,必须有某种存储。问题是在73行中,for循环借用了self.nodes,在89self.nodes行中,必须可变地借用以减少引用计数 -
如果将
self.nodes更改为Vec<RefCell<Node>>,那么即使在for循环中借用self.nodes,您也可以执行node.borrow_mut().ref_count += 1;。 -
哦,好的,我以为你的意思是
stack是RefCell。我的错。我会在一分钟内检查出来。谢谢 -
stack变量可以是Vec<Ref<Node>>,然后像这样推入这个向量:stack.push(node.borrow());吗?这个场景下的Ref<Node>是不是也用stack?
标签: rust