我有使用Rust 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_parser
和nom_parser
有何不同?谁在借buf?我应该如何更改程序以放置借阅检查器?
答案 0 :(得分:4)
let res = nom_parser(&buf)?.1;
^ here
您正在使用?
运算符将错误传播到main
中。 IResult<&[u8], String, u32>
= Result<(&[u8], String), nom::Err<&[u8], u32>>
。因此,如果发生错误,&buf
将作为其一部分返回,因此即使main
函数退出后它也必须保持活动状态,但这不会因为buf
是{{ 1}}。
在您的情况下,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!
,表示在解析过程中确实出了点问题。根据情况,您可能会将它们全部视为失败,或者以不同的方式处理它们。
答案 1 :(得分:0)
问题似乎出在IResult<I, O, E = u32>
上,并扩展到Result<(I, O), Err<I, E>>
如您所见,当您使用?
时,您可能返回的Err
仍可以包含对类型I(即您的&[u8]
)的引用,并从您的功能。
该函数返回此引用的唯一方法是该引用的生存期不以该函数'static
一个简单的解决方案是将&[u8]
更改为Vec<u8>
,即使我不确定您要如何处理它。