提问人:user1055947 提问时间:8/13/2023 最后编辑:user1055947 更新时间:8/13/2023 访问量:45
带有 Rust 的 RAII 风格防护给出无效的生命周期错误
RAII style guard with Rust gives invalid lifetime errors
问:
我正在编写词法分析器,并希望使用 RAII 帮助程序前进/备份游标。我有一个字符串,它由充当游标的类型索引。它是在顶层创建的,带有父保护,或者从父保护扩展而来。我相信以下代码正确地模拟了生存期:是 ' 的子生存期,但编译器仍然给出CharStreamGuard
new
extend
'c
b
error[E0597]: `csg` does not live long enough
--> src/lib.rs:78:48
|
76 | let mut csg = CharStreamGuard::new(&s);
| ------- binding `csg` declared here
77 | {
78 | let mut csg2 = CharStreamGuard::extend(&mut csg);
| ^^^^^^^^ borrowed value does not live long enough
...
82 | }
| -
| |
| `csg` dropped here while still borrowed
| borrow might be used here, when `csg` is dropped and runs the `Drop` code for type `CharStreamGuard`
error[E0499]: cannot borrow `csg` as mutable more than once at a time
--> src/lib.rs:81:5
|
78 | let mut csg2 = CharStreamGuard::extend(&mut csg);
| -------- first mutable borrow occurs here
...
81 | csg.accept();
| ^^^
| |
| second mutable borrow occurs here
| first borrow later used here
对于代码:
#[derive(PartialEq)]
enum GuardStatus {
Unset,
Accepted,
Rejected,
}
pub struct CharStreamGuard<'a, 'b> {
src: &'a String,
parent: Option<&'b mut CharStreamGuard<'a, 'b>>,
index: usize,
status: GuardStatus
}
impl<'a,'b> CharStreamGuard<'a,'b> {
fn new(src: &'a String) -> CharStreamGuard<'a,'b> {
return CharStreamGuard {
src: src,
parent: None,
index: 0,
status: GuardStatus::Unset
};
}
fn extend<'c>(parent: &'c mut CharStreamGuard<'a,'b>) -> CharStreamGuard<'a,'c>
where 'c : 'b
{
let index = parent.index;
return CharStreamGuard {
src: parent.src,
parent: Some(parent),
index: index,
status: GuardStatus::Unset
};
}
fn accept(&mut self) {
self.status = GuardStatus::Accepted;
if let Some(parent) = self.parent.as_mut() {
parent.index = self.index;
}
}
fn reject(&mut self) {
self.status = GuardStatus::Rejected;
}
}
impl Drop for CharStreamGuard<'_,'_> {
fn drop(&mut self) -> () {
if self.status == GuardStatus::Unset {
panic!("guard was neither accpeted nor rejected!");
}
}
}
fn test_it() {
let s = String::new();
let mut csg = CharStreamGuard::new(&s);
{
let mut csg2 = CharStreamGuard::extend(&mut csg);
csg2.accept();
}
csg.accept();
}
答:
0赞
user1055947
8/13/2023
#1
一个有效的解决方案,使用:Rc<RefCell<T>>
#[derive(PartialEq)]
enum GuardStatus {
Unset,
Accepted,
Rejected,
}
pub struct CharStreamGuard<'a> {
src: &'a String,
// parent: Option<&'b mut CharStreamGuard<'a, 'b>>,
parent: Option<Rc<RefCell<CharStreamGuard<'a>>>>,
index: usize,
status: GuardStatus
}
impl<'a> CharStreamGuard<'a> {
fn new(src: &'a String) -> CharStreamGuard<'a> {
return CharStreamGuard {
src: src,
parent: None,
index: 0,
status: GuardStatus::Unset
};
}
fn extend(parent: Rc<RefCell<CharStreamGuard<'a>>>) -> CharStreamGuard<'a>
{
let index = parent.borrow().index;
let src = parent.borrow().src;
return CharStreamGuard {
src: src,
parent: Some(parent),
index: index,
status: GuardStatus::Unset
};
}
fn accept(&mut self) {
self.status = GuardStatus::Accepted;
if let Some(parent) = self.parent.as_mut() {
parent.borrow_mut().index = self.index;
}
}
fn reject(&mut self) {
self.status = GuardStatus::Rejected;
}
}
impl Drop for CharStreamGuard<'_> {
fn drop(&mut self) -> () {
if self.status == GuardStatus::Unset {
panic!("guard was neither accpeted nor rejected!");
}
}
}
fn test_it() {
let s = String::new();
let mut csg = Rc::new(RefCell::new(CharStreamGuard::new(&s)));
{
let mut csg2 = CharStreamGuard::extend(csg.clone());
csg2.accept();
}
csg.borrow_mut().accept();
}
评论