Есть ли способ освободить привязку до того, как она выйдет из области видимости?

Я пытаюсь проанализировать файл с помощью регулярных выражений:

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
    }
}
Другие вопросы по тегам