Nom解析器借用检查问题

6

我有一个使用nom 4.2.2的Rust程序。(我已经扩展了nom解析器函数)

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_parsernom_parser有何不同?谁在借用buf?我应该如何修改程序以满足借用检查器的要求?

2个回答

10
let res = nom_parser(&buf)?.1;
                          ^ here

您正在使用?运算符将错误传递出main函数。类型IResult<&[u8], String, u32> = Result<(&[u8], String), nom::Err<&[u8], u32>>。因此,在发生错误的情况下,&buf作为其一部分返回,因此它必须在main函数退出后继续存在,但事实上不会,因为bufmain函数内的局部变量。

在您的情况下,nom_parser从未返回错误,但验证只关心类型和函数签名。

要解决此问题,您需要在将错误向上传递之前对其进行某种处理。例如:

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

请注意,在IResult中的Err并不总是硬错误。它可能是nom::Err::Incomplete,这意味着如果提供更多数据,则可以成功解析,或者是nom::Err::Error,这意味着输入未被解析器匹配(因此在alt!中的另一个解析器可能会成功),或者是nom::Err::Failure,这意味着在解析期间发生了一些非常严重的错误。根据情况,您可以将它们都视为失败或以不同的方式处理。

谢谢,这似乎确实是情况!将错误映射到一个新的带有旧错误字符串的错误中就解决了问题。真正的代码使用CompleteStr,因此不应该出现不完整数据的“问题”。 - Bittrance

0

问题似乎出现在 IResult<I, O, E = u32> 中,它扩展为 Result<(I, O), Err<I, E>>

正如您所看到的,当您使用 ? 时,您可能返回的 Err 仍然可以包含对类型 I 的引用,即您的 &[u8],并从函数中返回。

函数返回此引用的唯一方法是该引用具有不以函数结束为生命周期的 'static

解决您问题的简单方法是将 &[u8] 更改为 Vec<u8>,即使我不确定您试图做什么。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接