我想迭代两个嵌套向量 (Playground):
struct Name {
index: usize,
data: Vec<String>,
}
impl Name {
fn new(test: bool) -> Option<Name> {
if test {
Some(Name {
index: 0,
data: vec![String::from("ATGCTA"), String::from("ACGTGA")],
})
} else {
None
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
self.index += 1;
if self.index < self.data.len() {
Some(self.data[self.index - 1].as_bytes())
} else {
None
}
}
}
struct Data {
index: usize,
data: Vec<Option<Name>>,
}
impl Data {
fn new() -> Data {
Data {
index: 0,
data: vec![Name::new(true)],
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
let max_index = self.data.len() - 1;
let record = self.data[self.index].as_mut().unwrap().iter_record();
match record {
None => {
if self.index < max_index {
self.index += 1;
return self.iter_record();
}
}
_ => {}
}
record
}
}
fn main() {
let mut data = Data::new();
while let Some(ret) = data.iter_record() {
println!("{:?}", ret);
}
}
这是构建错误:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:47:28
|
40 | fn iter_record(&mut self) -> Option<&[u8]> {
| - let's call the lifetime of this reference `'1`
41 | let max_index = self.data.len() - 1;
42 | let record = self.data[self.index].as_mut().unwrap().iter_record();
| --------- first mutable borrow occurs here
...
47 | return self.iter_record();
| ^^^^ second mutable borrow occurs here
...
52 | record
| ------ returning this value requires that `self.data` is borrowed for `'1`
为什么会出现这个错误?我该如何解决?
答案 0 :(得分:2)
问题是 NLL 的 some parts 没有在编译器中实现,因为它们太占用 CPU。因此,编译器无法识别借用没有扩展到 match
之外。在一般情况下,解决方法是将其包装在一个无条件返回的 if
语句中。缺点是代码在运行时会变慢,因为它需要做两次相同的检查。这种机制在链接文档中得到了更好的解释。
fn iter_record(&mut self) -> Option<&[u8]> {
let max_index = self.data.len() - 1;
// This will not really work in your case, because you are modifying the struct's state, thus each method invocation will produce a different result
let check = self.data[self.index].as_mut().unwrap().iter_record();
if check.is_some() {
match self.data[self.index].as_mut().unwrap().iter_record() {
Some(r) => return Some(r),
None => unreachable!(),
}
}
if self.index < max_index {
self.index += 1;
return self.iter_record();
}
None
}
不幸的是,在您的情况下,这不起作用,因为您的 Name::iter_record()
修改了结构的内部状态,因此不可能调用它两次。为了解决这个问题,我将引入一个新方法 peek_record()
,它只返回 true
或 false
,具体取决于 iter_record()
是否会返回 Some
或None
如果改为调用:
fn peek_record(&self) -> bool {
self.index + 1 < self.data.len()
}
这将导致以下 working code:
struct Name {
index: usize,
data: Vec<String>,
}
impl Name {
fn new(test: bool) -> Option<Name> {
if test {
Some(Name {
index: 0,
data: vec![String::from("ATGCTA"), String::from("ACGTGA")],
})
} else {
None
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
self.index += 1;
if self.index < self.data.len() {
Some(self.data[self.index - 1].as_bytes())
} else {
None
}
}
fn peek_record(&self) -> bool {
self.index + 1 < self.data.len()
}
}
struct Data {
index: usize,
data: Vec<Option<Name>>,
}
impl Data {
fn new() -> Data {
Data {
index: 0,
data: vec![Name::new(true)],
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
let max_index = self.data.len() - 1;
if self.data[self.index].as_mut().unwrap().peek_record() {
match self.data[self.index].as_mut().unwrap().iter_record() {
Some(r) => return Some(r),
None => unreachable!(),
}
}
if self.index < max_index {
self.index += 1;
return self.iter_record();
}
None
}
}
fn main() {
let mut data = Data::new();
while let Some(ret) = data.iter_record() {
println!("{:?}", ret);
}
}
PS:你可以通过去掉递归来进一步简化你的代码:
fn iter_record(&mut self) -> Option<&[u8]> {
for idx in self.index..self.data.len() {
if self.data[idx].as_mut().unwrap().peek_record() {
match self.data[idx].as_mut().unwrap().iter_record() {
Some(r) => return Some(r),
None => unreachable!(),
}
}
self.index += 1;
}
None
}