#rust
Вопрос:
Я хочу повторить два вложенных вектора (игровая площадка):
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(amp;mut self) -> Option<amp;[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(amp;mut self) -> Option<amp;[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(amp;mut self) -> Option<amp;[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`
Почему возникает эта ошибка? Как мне ее решить?
Комментарии:
1. нужно ли его вызывать рекурсивно? Вместо этого вы могли бы написать цикл while.
2. Я попробовал цикл, но получил аналогичную ошибку.
Ответ №1:
Проблема в том, что некоторые части NLL не были реализованы в компиляторе, потому что они слишком загружены процессором. В результате компилятор не может распознать, что заимствование не распространяется за пределы match
. В общем случае обходной путь состоит в том, чтобы обернуть его в if
оператор, который безоговорочно возвращает. Недостатком является то, что код будет работать медленнее во время выполнения, потому что ему нужно будет дважды выполнить одну и ту же проверку. Этот механизм гораздо лучше объяснен в связанном документе.
fn iter_record(amp;mut self) -> Option<amp;[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(amp;self) -> bool {
self.index 1 < self.data.len()
}
Это приведет к следующему рабочему коду:
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(amp;mut self) -> Option<amp;[u8]> {
self.index = 1;
if self.index < self.data.len() {
Some(self.data[self.index - 1].as_bytes())
} else {
None
}
}
fn peek_record(amp;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(amp;mut self) -> Option<amp;[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(amp;mut self) -> Option<amp;[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
}
Комментарии:
1. Спасибо за ваше объяснение и код, в последнем блоке кода есть ошибка,
self.index = 1;
ее следует поместить в блок else.2. @Moold ты прав. На самом
self.index = 1;
деле его можно переместить послеif
, потому что он всегда возвращается, когда он принимает значение true3. «NLL» означает не лексическое время жизни .