2016-08-27 2 views
3

Я хочу, чтобы извлечь все названные группы из матча в HashMap, и я бег в «не живет достаточно долго,» ошибку при попытке скомпилировать этот код:Перебор названных групп регулярных выражений в Rust

extern crate regex; 

use std::collections::HashMap; 
use regex::Regex; 

pub struct Route { 
    regex: Regex, 
} 

pub struct Router<'a> { 
    pub namespace_seperator: &'a str, 
    routes: Vec<Route>, 
} 

impl<'a> Router<'a> { 
    // ... 

    pub fn path_to_params(&self, path: &'a str) -> Option<HashMap<&str, &str>> { 
     for route in &self.routes { 
      if route.regex.is_match(path) { 
       let mut hash = HashMap::new(); 
       for cap in route.regex.captures_iter(path) { 
        for (name, value) in cap.iter_named() { 
         hash.insert(name, value.unwrap()); 
        } 
       } 
       return Some(hash); 
      } 
     } 
     None 
    } 
} 

fn main() {} 

Вот результат ошибки:

error: `cap` does not live long enough 
    --> src/main.rs:23:42 
    |> 
23 |>      for (name, value) in cap.iter_named() { 
    |>           ^^^ 
note: reference must be valid for the anonymous lifetime #1 defined on the block at 18:79... 
    --> src/main.rs:18:80 
    |> 
18 |>  pub fn path_to_params(&self, path: &'a str) -> Option<HashMap<&str, &str>> { 
    |>                    ^
note: ...but borrowed value is only valid for the for at 22:16 
    --> src/main.rs:22:17 
    |> 
22 |>     for cap in route.regex.captures_iter(path) { 
    |>    ^

Очевидно, у меня есть еще одно или два, чтобы узнать о Ржавчина жизни.

ответ

3

Давайте проследим за прижизненные линии:

  • route.regex.captures_iter(path) создает FindCapture<'r, 't> где время жизни 'r является то, что route.regex и время жизни 't является то, что path
  • этот итератор дает Captures<'t>, только связана с временем жизни от path
  • , метод которого iter_named(&'t self) дает значение SubCapture<'t>, связанное со временем жизни pathи время жизни cap
  • этот итератор дает (&'t str, Option<&'t str>) так, что оба ключа и значение HashMap связаны с временем жизни pathи время жизни cap

Поэтому его к сожалению, невозможно пережить переменную cap, так как эта переменная используется кодом как «маркер», чтобы сохранить буферы, содержащие группы в живых.

Я боюсь, что единственным решением без существенной реструктуризации является возврат HashMap<String, String>, как неудовлетворительный, как есть. Мне также приходит в голову, что одна группа захвата может совпадать с несколько раз раз, не уверен, хотите ли вы побеспокоиться об этом.

+0

Благодарим вас за разъяснения по срокам службы. К сожалению, я по-прежнему получаю ту же ошибку с этим новым намеком: примечание: ссылка должна быть действительной для срока службы «b», как определено на блоке в 39:92 ​​... pub fn path_to_params <'b> (& 'b self, path: &' b str) -> Вариант > { – eltiare

+0

Нужно ли устанавливать срок действия кепки? Если да, то как мне это сделать? Для циклов кажется более сложным. – eltiare

+0

@eltiare: Обратите внимание, что я не ставил '' b' столько мест, сколько вы. Я оставил его «self» и ключи «HashMap». Разве это не сработало без него? –

1

Matthieu M. already explained срок службы хорошо. Хорошей новостью является то, что ящик регулярных выражений распознал проблему и there's a fix in the pipeline for 1.0.

Как указано в сообщении фиксации:

Всегда можно было обойти эту проблему с помощью индексов.

Это также возможных обойти эту проблему с помощью Regex::capture_names, хотя это немного более вложенного таким образом:

pub fn path_to_params(&self, path: &'a str) -> Option<HashMap<&str, &str>> { 
    for route in &self.routes { 
     if let Some(captures) = route.regex.captures(path) { 
      let mut hash = HashMap::new(); 
      for name in route.regex.capture_names() { 
       if let Some(name) = name { 
        if let Some(value) = captures.name(name) { 
         hash.insert(name, value); 
        } 
       } 
      } 
      return Some(hash); 
     } 
    } 
    None 
} 

Обратите внимание, что я также удалить внешнюю is_match - это неэффективно для запуска regex один раз и снова.

+0

Является ли он еще более эффективным, если у вас есть много регулярных выражений, чтобы соответствовать? – eltiare

+0

@eltiare вы всегда должны проверять смелые заявления от людей в Интернете ;-) Бенчмаркинг был бы хорошей идеей. При этом я не могу представить, что метод захвата был бы в несколько раз более сложным; моя кишка говорит, может быть, на 5% медленнее. Это означало бы, что 20 регулярных выражений были бы переломным моментом (если вы всегда проверяли все 20). Бенчмаркинг был бы интересным! – Shepmaster

Смежные вопросы