Есть ли способ освободить привязку до того, как она выйдет из области видимости?
Я пытаюсь проанализировать файл с помощью регулярных выражений:
extern crate regex; // 1.0.1
use regex::Regex;
fn example(
section_header_pattern: Regex,
section_name: &str,
mut line: String,
mut is_in_right_section: bool,
) {
loop {
if let Some(m) = section_header_pattern
.captures(&line)
.and_then(|c| c.get(1))
{
is_in_right_section = m.as_str().eq(section_name);
line.clear();
continue;
}
}
}
fn main() {}
... но компилятор жалуется, потому что RegEx
"s captures()
Метод имеет заимствование, которое длится в течение жизни матча:
error[E0502]: cannot borrow `line` as mutable because it is also borrowed as immutable
--> src/main.rs:17:13
|
13 | .captures(&line)
| ---- immutable borrow occurs here
...
17 | line.clear();
| ^^^^ mutable borrow occurs here
18 | continue;
19 | }
| - immutable borrow ends here
Когда я доберусь до line.clear();
Я сделал с Match
и хотел бы очистить буфер и перейти к следующей строке в файле без дальнейшей обработки. Есть ли хорошее / чистое / элегантное / идиоматическое решение или мне нужно просто прикусить пулю и ввести следующий блок "если"?
1 ответ
Краткий ответ: Нет.
Я сделал с
Match
Возможно, но компилятор этого не знает. В частности, время жизни в настоящее время связано с лексической областью, в которой они определены. Функция, которую вы ищете, называется нелексической продолжительностью жизни. Сейчас он не стабилен, но его планируется включить в выпуске Rust 2018.
В качестве примера:
fn main() {
let mut s = String::from("hello");
let matched = &s[..];
println!("{}", matched);
s.clear();
println!("{}", s);
}
Программист может сказать, что мы закончили matched
после того, как мы его распечатаем, но компилятор говорит, что заимствование длится до закрытия }
, Исправление состоит в том, чтобы ввести область действия:
fn main() {
let mut s = String::from("hello");
{
let matched = &s[..];
println!("{}", matched);
}
s.clear();
println!("{}", s);
}
Ваш случай более коварен, поскольку решение очистить строку переплетается со значением заимствования самой строки. Что-то вроде этого было бы моим первым местом для достижения:
fn main() {
let mut s = String::from("hello");
let do_clear;
{
let matched = &s[..];
println!("{}", matched);
do_clear = matched.contains("ll");
}
if do_clear {
s.clear();
}
println!("{}", s);
}
Тем не менее, ваш конкретный случай может быть преобразован, чтобы избежать if
/ if let
заявления:
let is_in_right_section = section_header_pattern.captures(&line)
.and_then(|c| c.get(1))
.map_or(false, |m| m.as_str() == section_name);
if is_in_right_section {
line.clear();
continue;
}
Что не будет выглядеть слишком плохо, если вы введете новый тип и / или метод. В качестве бонуса есть место для Regex
жить:
struct Section(Regex);
impl Section {
fn is(&self, s: &str, section: &str) -> bool {
self.0
.captures(s)
.and_then(|c| c.get(1))
.map_or(false, |m| m.as_str() == section)
}
}
// ----
if section.is(&line, section_name) {
line.clear();
continue;
}
Исходный код работает как есть, когда включен NLL:
#![feature(nll)]
extern crate regex; // 1.0.1
use regex::Regex;
fn main() {
let section_header_pattern = Regex::new(".").unwrap();
let section_name = "";
let mut line = String::new();
let mut is_in_right_section = false;
loop {
if let Some(m) = section_header_pattern
.captures(&line)
.and_then(|c| c.get(1))
{
is_in_right_section = m.as_str().eq(section_name);
line.clear();
continue;
}
return; // I don't really want to loop
}
}