我有一个简单的trie实现,其中 Edge
包含一个字符和对另一个 Node
的引用:
struct Edge<'a> {
ch: char,
to: &'a Node<'a>,
}
a Node
包含一个边的向量:
pub struct Node<'a> {
edges: Vec<Edge<'a>>,
}
我正在尝试实现该方法将字符插入节点。我认为返回值应该是对Node
的引用:如果字符已经在其中一个边缘中,则直接返回现有的Node
;如果没有,我们返回新创建的Node
。这是我陷入麻烦的地方:
impl<'a> Node<'a> {
fn get_or_create(&mut self, ch: char) -> &Node<'a> {
match self.edges.binary_search_by(|e| e.ch.cmp(&ch)) {
Ok(idx) => {
return &self.edges.get(idx).unwrap().to;
}
Err(idx) => {
let to = &Node { edges: Vec::new() };
let e = Edge { ch: ch, to: to };
self.edges.insert(idx, e);
return to;
}
}
}
}
据说to
的寿命不够长。
我很确定我写的东西远非惯用生锈。最初,当我在Edge
中包括对Node
的引用时,我没有添加寿命参数,并提示这样做,然后我必须到处添加它。但是看起来很奇怪。我想知道正确的方法是什么?
也许我真正使用的是Edge
中的其他包装器类型抽象,以参考堆分配的Node
,例如。Box
?我将仔细阅读有关此主题的部分。
此数据结构无法按设计工作。红旗是以下句子:
我认为返回值应该是对
Node
的引用:如果字符已经在一个边缘中,则直接返回现有的Node
;如果没有,我们返回新创建的Node
。
代码未返回新创建的节点,它试图将A 参考返回到新创建的节点。仅当对象存储在将其超过参考的地方时,返回对象的引用才安全。否则,引用最终将指向对象用于驻留的堆栈上的位置,从而导致使用时崩溃。像这样的错误是C和C 的经常出现的崩溃来源,正是Rust借用检查器旨在预防的错误。
Rust在功能和数据上使用寿命参数跟踪参考寿命。为了证明参考不会超过对象,Rust禁止参考的寿命超出对象的寿命。由于新节点在功能末尾删除,并且从函数返回引用,因此对象的寿命太短,并且代码正确拒绝为无效。
有几个可能的修复:
-
直接将
Node
存储在Edge
中。显示了这是编译的。 -
将
&Node
更改为Rc<Node>
。这允许单个节点的共享所有权以多个边缘和自动DealLocation。
在这两种情况下,明确的终身管理将不再是必要的,所有权将"仅仅工作"。如果您知道C 11,则Rc<>
大致相当于std::shared_ptr
。