为什么这段代码:
#[derive(Eq, PartialEq, Ord, PartialOrd)]
enum List<'a> {
Cons(isize, &'a List<'a>),
Nil,
}
fn main() {
use List::*;
use pinus::{prelude::*, sync::PineMap};
let table = PineMap::new();
table.insert(Nil, Nil);
let nil = table.get(&Nil).unwrap();
table.insert(Cons(1, nil), Cons(1, nil));
}
导致此错误:
error[E0597]: `table` does not live long enough
--> src/main.rs:12:15
|
12 | let nil = table.get(&Nil).unwrap();
| ^^^^^^^^^^^^^^^ borrowed value does not live long enough
13 | table.insert(Cons(1, nil), Cons(1, nil));
14 | }
| -
| |
| `table` dropped here while still borrowed
| borrow might be used here, when `table` is dropped and runs the `Drop` code for type `PineMap`
我使用的是pinus::sync::PineMap(GitHub)来确保对List
的等价示例的所有引用实际上是对内存中同一对象的引用。我正在为它尝试PineMap
,因为它的insert
不会在内存中移动它的项(它的insert也借用了&self
,而不是&mut self
),所以对它的List
值的引用将保持有效,我可以构建自引用项。
为什么table
在我的代码中仍然被认为是在其作用域的末尾被借用的?
1条答案
按热度按时间fdbelqdn1#
当你把
nil
从表中取出来,然后把它放回表中,nil
的类型是一个与table
的生存期绑定的引用,因此你要存储的List
的生存期'a
绑定到存储它们的table
。这里的核心问题是,这会产生一个自引用结构体,这会带来无数的问题。你也不能调用任何可变方法,因为
table
永远不改变地借用了自己。编译器抱怨的具体问题是,由于元素持有对表的引用,因此当删除该元素时,删除逻辑可能会尝试访问正在被销毁的数据,这是不合理的。
我建议您阅读Rustonomicon中有关Drop Check的更多信息,但这里有一个指导原则:
要使泛型类型正确地实现drop,其泛型参数必须严格地比它的寿命长。
我没有任何变通办法或解决方案,你除了你不能这样做。