循环中的 Rust 生命周期问题
Rust lifetime issue in loop
如何在不复制数组或每次迭代多次调用 b()
的情况下编译此示例 — b()
必须执行一些昂贵的解析?
这不是我写的完整代码,但它说明了我遇到的问题。这里,Test
正在尝试执行某种流解析工作。 c()
为解析函数,解析成功时为returns Some
。 b()
是一个函数,当 c()
还不能使用可用数据进行解析时,它会尝试从流中读取更多数据。 returned 值是包含解析范围的 self.v
的切片。
struct Test {
v: [u8; 10],
index: u8,
}
impl Test {
fn b(&mut self) {
self.index = 1
}
fn c(i: &[u8]) -> Option<&[u8]> {
Some(i)
}
fn a(&mut self) -> &[u8] {
loop {
self.b();
match Test::c(&self.v) {
Some(r) => return r,
_ => continue,
}
}
}
}
fn main() {
let mut q = Test {
v: [0; 10],
index: 0,
};
q.a();
}
编译时,会产生以下借用检查器错误:
error[E0502]: cannot borrow `*self` as mutable because `self.v` is also
borrowed as immutable
--> <anon>:17:13
|
17 | self.b();
| ^^^^ mutable borrow occurs here
18 |
19 | match Test::c(&self.v) {
| ------ immutable borrow occurs here
...
24 | }
| - immutable borrow ends here
如果我将 a()
更改为:
fn a(&mut self) -> Option<&[u8]> {
loop {
self.b();
if let None = Test::c(&self.v) {
continue
}
if let Some(r) = Test::c(&self.v) {
return Some(r);
} else {
unreachable!();
}
}
}
然后它运行,但明显的缺点是调用解析函数 c()
两次。
我有点理解改变 self
而 return 值取决于它是不安全的,但是,我不明白为什么 self.v
的不可变借用仍然存在在下一次迭代中,当我们再次尝试调用 b()
时。
现在"Rustc can't "处理“有条件借款returns”。看到这个 comment from Gankro on issue 21906.
如果只有一个执行路径终止循环,则无法为借用分配正确的生命周期。
我可以建议这个解决方法,但我不确定它是否最佳:
fn c(i: &[u8]) -> Option<(usize, usize)> {
Some((0, i.len()))
}
fn a(&mut self) -> &[u8] {
let parse_result;
loop {
self.b();
match Test::c(&self.v) {
Some(r) => {
parse_result = r;
break;
}
_ => {}
}
}
let (start, end) = parse_result;
&self.v[start..end]
}
您可以使用数组索引构造解析结果,并将它们转换为循环外的引用。
另一种选择是诉诸 unsafe
来解耦生命周期。安全使用unsafe我不是专家,所以要注意别人的评论。
fn a(&mut self) -> &[u8] {
loop {
self.b();
match Test::c(&self.v) {
Some(r) => return unsafe{
// should be safe. It decouples lifetime of
// &self.v and lifetime of returned value,
// while lifetime of returned value still
// cannot outlive self
::std::slice::from_raw_parts(r.as_ptr(), r.len())
},
_ => continue,
}
}
}
如何在不复制数组或每次迭代多次调用 b()
的情况下编译此示例 — b()
必须执行一些昂贵的解析?
这不是我写的完整代码,但它说明了我遇到的问题。这里,Test
正在尝试执行某种流解析工作。 c()
为解析函数,解析成功时为returns Some
。 b()
是一个函数,当 c()
还不能使用可用数据进行解析时,它会尝试从流中读取更多数据。 returned 值是包含解析范围的 self.v
的切片。
struct Test {
v: [u8; 10],
index: u8,
}
impl Test {
fn b(&mut self) {
self.index = 1
}
fn c(i: &[u8]) -> Option<&[u8]> {
Some(i)
}
fn a(&mut self) -> &[u8] {
loop {
self.b();
match Test::c(&self.v) {
Some(r) => return r,
_ => continue,
}
}
}
}
fn main() {
let mut q = Test {
v: [0; 10],
index: 0,
};
q.a();
}
编译时,会产生以下借用检查器错误:
error[E0502]: cannot borrow `*self` as mutable because `self.v` is also
borrowed as immutable
--> <anon>:17:13
|
17 | self.b();
| ^^^^ mutable borrow occurs here
18 |
19 | match Test::c(&self.v) {
| ------ immutable borrow occurs here
...
24 | }
| - immutable borrow ends here
如果我将 a()
更改为:
fn a(&mut self) -> Option<&[u8]> {
loop {
self.b();
if let None = Test::c(&self.v) {
continue
}
if let Some(r) = Test::c(&self.v) {
return Some(r);
} else {
unreachable!();
}
}
}
然后它运行,但明显的缺点是调用解析函数 c()
两次。
我有点理解改变 self
而 return 值取决于它是不安全的,但是,我不明白为什么 self.v
的不可变借用仍然存在在下一次迭代中,当我们再次尝试调用 b()
时。
现在"Rustc can't "处理“有条件借款returns”。看到这个 comment from Gankro on issue 21906.
如果只有一个执行路径终止循环,则无法为借用分配正确的生命周期。
我可以建议这个解决方法,但我不确定它是否最佳:
fn c(i: &[u8]) -> Option<(usize, usize)> {
Some((0, i.len()))
}
fn a(&mut self) -> &[u8] {
let parse_result;
loop {
self.b();
match Test::c(&self.v) {
Some(r) => {
parse_result = r;
break;
}
_ => {}
}
}
let (start, end) = parse_result;
&self.v[start..end]
}
您可以使用数组索引构造解析结果,并将它们转换为循环外的引用。
另一种选择是诉诸 unsafe
来解耦生命周期。安全使用unsafe我不是专家,所以要注意别人的评论。
fn a(&mut self) -> &[u8] {
loop {
self.b();
match Test::c(&self.v) {
Some(r) => return unsafe{
// should be safe. It decouples lifetime of
// &self.v and lifetime of returned value,
// while lifetime of returned value still
// cannot outlive self
::std::slice::from_raw_parts(r.as_ptr(), r.len())
},
_ => continue,
}
}
}