вопрос проверки парсера заимствования - PullRequest
2 голосов
/ 15 марта 2019

У меня есть эта программа Rust, использующая ном 4.2.2.(Я взял на себя смелость расширения функции nom parser.)

extern crate failure;
extern crate nom;

use failure::Error;
use std::fs::File;
use std::io::Read;

fn nom_parser(i: &[u8]) -> ::nom::IResult<&[u8], String, u32> {
    { ::nom::lib::std::result::Result::Ok((i, ("foo".to_owned()))) }
}

fn my_parser(buf: &[u8]) -> Result<(&[u8], String), Error> {
  Ok((buf, "foo".to_owned()))
}

fn main() -> Result<(), Error> {
  let handler = |mut entries: String| { entries.clear() };
  loop {
    let mut buf = Vec::new();
    File::open("/etc/hosts")?.read_to_end(&mut buf)?;
    let res = nom_parser(&buf)?.1;
    // let res = my_parser(&buf)?.1;
    handler(res);
  }
}

Компиляция этой программы с rustc 1.33.0 (2aa4c46cf 2019-02-28) приводит к следующей проблеме:

error[E0597]: `buf` does not live long enough
  --> nom-parsing/src/main.rs:21:26
   |
21 |     let res = nom_parser(&buf)?.1;
   |               -----------^^^^-
   |               |          |
   |               |          borrowed value does not live long enough
   |               argument requires that `buf` is borrowed for `'static`
...
24 |   }
   |   - `buf` dropped here while still borrowed

Переключение на закомментированную версиюпарсера компилируется просто отлично.Чем отличаются my_parser и nom_parser?Кто одолжил буф?Как мне изменить программу, чтобы успокоить заемщика?

Ответы [ 2 ]

4 голосов
/ 15 марта 2019
let res = nom_parser(&buf)?.1;
                          ^ here

Вы используете оператор ? для распространения ошибки из main. IResult<&[u8], String, u32> = Result<(&[u8], String), nom::Err<&[u8], u32>>. Таким образом, в случае ошибки &buf возвращается как часть его, поэтому он должен оставаться в живых даже после выхода из main функции, но не будет, потому что buf является локальной переменной внутри main.

В вашем случае nom_parser никогда не возвращает ошибку, но проверка касается только типов и сигнатур функций.

Чтобы исправить это, вы должны как-то обработать ошибку, прежде чем распространять ее. Например:

let res = nom_parser(&buf).map_err(|_| failure::format_err!("Parsing failed!"))?.1;

Обратите внимание, что Err в IResult не всегда серьезная ошибка . Это может быть nom::Err::Incomplete, что означает, что синтаксический анализ может завершиться успешно, если будет предоставлено больше данных, или nom::Err::Error, означающее, что синтаксический анализатор не сопоставил входные данные (так что, возможно, другой синтаксический анализатор в alt! может завершиться успешно), или nom::Err::Failure Это означает, что во время анализа что-то пошло не так. В зависимости от ситуации вы можете рассматривать их как сбой или обращаться с ними по-разному.

0 голосов
/ 15 марта 2019

Кажется, проблема в IResult<I, O, E = u32>, что превышает Result<(I, O), Err<I, E>>

Как вы можете видеть, когда вы используете ?, Err, который вы можете вернуть, может все еще содержать ссылку на тип I, который является вашим &[u8], и возвращаться из вашей функции.

Единственный способ для функции вернуть эту ссылку состоит в том, что у ссылки есть время жизни, которое не заканчивается функцией, 'static

Простым решением вашей проблемы было бы заменить &[u8] на Vec<u8>, даже если я не уверен, что вы пытаетесь с ним делать.

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