Я новичок в Rust, и в настоящее время у меня проблема с проверкой заимствований. Этот код не компилируется:
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut out = String::new();
let mut xs = self.xs.iter();
for x in 0..11 {
out += match x {
3 | 7 => "|",
_ => &xs.next().unwrap().to_string(),
};
}
write!(f, "{}", out)
}
я получаю ошибку
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:32:23
|
30 | out += match x {
| ____________________-
31 | | 3 | 7 => "|",
32 | | _ => &xs.next().unwrap().to_string(),
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| | | |
| | | temporary value is freed at the end of this statement
| | creates a temporary which is freed while still in use
33 | | };
| |_____________- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Однако этот очень похожий код компилируется: (конечно, не с той функциональностью, которую я ищу)
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut out = String::new();
let mut xs = self.xs.iter();
for x in 0..11 {
out += &xs.next().unwrap().to_string();
}
write!(f, "{}", out)
}
Мой вопрос: почему первый пример не работает, если работает второй? Насколько я понимаю, match
следует просто оценивать как то, что оно возвращает, поэтому в случае, когда x
не равно 3 или 7, оно должно быть функционально таким же, как во втором примере.
Благодарю вас!
Руки в match
могут быть блоками со своими утверждениями. Результатом этого является то, что временные элементы, созданные в руке match
, сбрасываются при выходе из руки. Таким образом, временное String
, созданное xs.next().unwrap().to_string()
, уничтожается до того, как может быть выполнено добавление-назначение, но рука пытается вернуть заимствование против временного, что приводит к висячей ссылке.
Второй пример, который вы показываете, не имеет этой проблемы, потому что он не использует match
(или другую блочную конструкцию, такую как if
), и поэтому временный объект существует до тех пор, пока после не будет выполнено добавление-назначение.
Один из способов обойти это — заставить обе руки match
возвращать String
:
out += match x {
3 | 7 => "|".to_string(),
_ => xs.next().unwrap().to_string(),
};
(Если вам нужно, чтобы match
оценивалось как &str
, вы можете позаимствовать результат с помощью &match x { ... }
, но здесь это не обязательно.)
Конечно, это добавляет дополнительное распределение в случае 3 | 7
, но необходимо для согласования типов рук match
.
Вместо этого рассмотрите возможность выполнения add-assign внутри match
. При таком подходе проблема согласования типов рук уходит, а также решается проблема временного существования:
match x {
3 | 7 => { out += "|"; }
_ => { out += xs.next().unwrap().to_string(); }
};