Почему std :: loan :: Cow явно требуется при отображении строк с помощью регулярных выражений? - PullRequest
0 голосов
/ 18 сентября 2018

Я реализую синтаксический анализатор в структуре Parser.Я выставляю метод pub lines для перебора строк кода с удаленными комментариями.Я хочу вернуть Box<Iterator>

extern crate regex; // 1.0.5

use regex::Regex;

pub struct Parser {
    code: String,
}

static comment: Regex = Regex::new(r"//.*$").unwrap();

impl Parser {
    pub fn new(code: String) -> Parser {
        Parser { code }
    }

    pub fn lines(&self) -> Box<Iterator<Item = &str>> {
        let lines = self
            .code
            .split("\n")
            .map(|line| comment.replace_all(line, ""));
        Box::new(lines)
    }
}

Однако компилятор выдаёт эту ошибку:

error[E0271]: type mismatch resolving `<[closure@src/lib.rs:20:18: 20:54] as std::ops::FnOnce<(&str,)>>::Output == &str`
  --> src/lib.rs:21:9
   |
21 |         Box::new(lines)
   |         ^^^^^^^^^^^^^^^ expected enum `std::borrow::Cow`, found &str
   |
   = note: expected type `std::borrow::Cow<'_, str>`
              found type `&str`
   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Map<std::str::Split<'_, &str>, [closure@src/lib.rs:20:18: 20:54]>`
   = note: required for the cast to the object type `dyn std::iter::Iterator<Item=&str>`

Он хочет, чтобы я использовал std::borrow::Cow,но я не могу найти ничего в Map документах , где упоминается это требование.Почему это необходимо?Могу ли я избежать этого?

Ответы [ 3 ]

0 голосов
/ 19 сентября 2018

Как вы уже обнаружили, Cow происходит от Regex::replace_all

В вашем случае очень опасен и обескуражен способ получить итератор из &str:

extern crate regex; // 1.0.5

use regex::Regex;
use std::borrow::Cow;

pub struct Parser {
    code: String,
}

impl Parser {
    pub fn new(code: String) -> Parser {
        Parser { code }
    }

    pub fn lines<'a>(&'a self, comment: Regex) -> Box<Iterator<Item = &'a str> + 'a> {
        let lines = self
            .code
            .split("\n")
            .map(move |line| comment.replace_all(line, ""))
            .map(|cow| match cow {
                Cow::Borrowed(sref) => sref,
                Cow::Owned(_) => panic!("I hope never to be here"),
            });
        Box::new(lines)
    }
}

fn main() {
    let comment: Regex = Regex::new(r"//.*$").unwrap();

    let p = Parser::new("hello\nworld".to_string());

    for item in p.lines(comment) {
        println!("{:?}", item);
    }
}

Это работает, потому что нет Cow s, которые бы выделяли строки.

Лучшим способом может быть возврат итератораString с:

pub fn lines<'a>(&'a self, comment: Regex) -> Box<Iterator<Item = String> + 'a> {
    let lines = self
        .code
        .split("\n")
        .map(move |line| comment.replace_all(line, ""))
        .map(|cow| cow.into_owned());

    Box::new(lines)
}
0 голосов
/ 19 сентября 2018

Вот лучшее решение для моего случая.

replace_all не является хорошим методом для этого случая использования.Я просто хочу удалить комментарии.Мне никогда не нужно ничего вставлять в строку.Если это так, я должен просто иметь возможность работать с кусочками строк.Нет необходимости в типе Cow, представленном replace_all.Вот как я это сделал вместо этого.

impl Parser {
    pub fn lines<'a>(&'a self) -> Box<dyn Iterator<Item = &'a str> + 'a> {
        let lines = self.code
            .lines()
            .map(|line| { line.split("//").next().unwrap() })
            .map(|line| line.trim())
            .filter(|line| line.len() > 0);

        Box::new(lines)
    }
}
0 голосов
/ 18 сентября 2018

Настоятельно рекомендуется прочитать документацию для всех типов и методов, которые вы используете.Например, Regex::replace_all задокументировано как:

pub fn replace_all<'t, R: Replacer>(
    &self, 
    text: &'t str, 
    rep: R
) -> Cow<'t, str>
//   ^^^^^^^^^^^^

Вот откуда взято Cow.

Невозможно вернуть итератор &str s, как только вы выделили новые строки;вам нужно будет выбрать новый тип итератора.Нечто подобное кажется возможным, но, поскольку ваш код не компилируется по причинам, отличным от этой проблемы времени жизни, я не могу легко это проверить.

pub fn lines<'a>(&'a self) -> Box<dyn Iterator<Item = Cow<'a, str>> + 'a>

См. Также:

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