Как передать измененные строковые параметры? - PullRequest
0 голосов
/ 04 июля 2018

Я нахожусь на главе 12 Rust Programming Language , где реализован поиск строки без учета регистра. Мне не имеет смысла реализовывать одну и ту же логику дважды, поэтому я подумал, что если бы я просто вызвал чувствительную к регистру функцию поиска с параметрами, преобразованными в нижний регистр, это могло бы сработать. Это не так.

Это мой нерабочий код:

fn main() {
    let a = search("Waldo", "where in\nthe world\nis Waldo?");
    let b = search("waldo", "where in\nthe world\nis Waldo?");
    let c = search_case_insensitive("waldo", "where in\nthe world\nis Waldo?");

    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let mut results = Vec::new();

    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }

    results
}

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let query = query.to_lowercase();
    let contents2: &str = &contents.to_lowercase();

    search(&query, contents2)
}

Ошибка в большинстве версий, с которыми я столкнулся, неизбежно очень похожа на:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:25:28
   |
25 |     let contents2: &str = &contents.to_lowercase();
   |                            ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
...
28 | }
   | - temporary value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 23:1...
  --> src/main.rs:23:1
   |
23 | pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

РЕДАКТИРОВАТЬ 2:

Поскольку вы обновили вопрос с помощью MCVE и заявили, что вам не нужно отказываться от примеров из книги ... вот еще одна версия, основанная на дополнительных распределениях с использованием String:

fn main() {
    let a = search("Waldo", "where in\nthe world\nis Waldo?");
    let b = search("waldo", "where in\nthe world\nis Waldo?");
    let c = search_case_insensitive("waldo", "where in\nthe world\nis Waldo?");

    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
}

pub fn search<S>(query: S, contents: S) -> Vec<String> where S: Into<String> {
    let query = query.into();
    let mut results = Vec::new();

    for line in contents.into().lines() {
        if line.contains(&query) {
            results.push(line.into());
        }
    }

    results

}

pub fn search_case_insensitive<S>(query: S, contents: S) -> Vec<String> where S: Into<String> {
    let query = query.into().to_lowercase();
    let contents = contents.into().to_lowercase();

    search(query, contents)
}

Вот он работает на детской площадке

EDIT:

Я понял, что никогда не давал тебе альтернативы. Вот что я, вероятно, сделал бы:

pub enum SearchOptions {
    CaseSensitive,
    CaseInsensitive
}

pub fn search<'a>(query: &str, contents: &'a str, options: SearchOptions) -> Vec<&'a str> {
    let mut results = Vec::new();

    for line in contents.lines() {
        let check = match options {
            SearchOptions::CaseSensitive => line.contains(query),   
            SearchOptions::CaseInsensitive => line.to_lowercase().contains(&query.to_lowercase()),   
        };

        if check {
            results.push(line);
        }
    }

    results
}

Это примерно настолько, насколько вы могли бы "обмануть" его.

Оригинальный ответ:

Реальная проблема заключается в том, что вы пытаетесь передать contents, когда он связан с временем жизни 'a ... но вы действительно хотите быть "нечувствительным к регистру" - это query.

Это никак не связано с продолжительностью жизни 'a точно так же, и поэтому ... работает:

pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let query = query.to_lowercase();
    search(&query, contents)
}

Вот она на детской площадке

Вам все равно придется дублировать логику, хотя ... потому что вам нужно сопоставить запрос в нижнем регистре со строкой в ​​нижнем регистре ..., что продемонстрировано в примерах в книге:

if line.to_lowercase().contains(&query) {
//      ^^^^^^^^^^^^^^ each LINE is converted to lowercase here in the insensitive search
    results.push(line);
}

"Как мне перестать дублировать логику?" - Ну, во-первых, они не совсем одинаковые. Я думаю, что ваша попытка была не совсем такой, какой вы были в первую очередь (хотя я рад, что ее исправили).

0 голосов
/ 04 июля 2018

Вы ввели невозможное ограничение на время жизни переменной contents2; записывая &'a, вы пытаетесь присвоить ему то же время жизни, что и аргументу contents, но оно создается и уничтожается в области действия search_case_insensitive и, таким образом, изживается contents.

Чтобы contents2 пережил тело search_case_insensitive, вам нужно либо вернуть его как String и присвоить какой-либо переменной за его пределами, либо передать его search_case_insensitive по ссылке, пока оно уже существует как String в другом месте.

Ссылаясь на Книга :

Важно понимать, что аннотации времени жизни описательный, а не предписывающий . Это означает, что как долго ссылка действительный определяется кодом, а не аннотациями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...