我遇到了生命周期问题,我不确定如何解决,因为我所做的改变对于生命周期来说应该是微不足道的。
鉴于:
use anyhow::Context;
use nom::{IResult, bytes::complete::tag};
以下代码编译:
let input = std::str::from_utf8(&output.stdout).unwrap();
let mut lines = input.lines();
let branch_line = lines.next().context("no output from `git status`")?;
let branch: IResult<&str, &str> = tag("On branch ")(branch_line);
let (branch, _) = branch.expect("failed to get name of current branch");
将最后一行中的
expect
更改为context
后,代码不再编译:
let input = std::str::from_utf8(&output.stdout).unwrap();
let mut lines = input.lines();
let branch_line = lines.next().context("no output from `git status`")?;
let branch: IResult<&str, &str> = tag("On branch ")(branch_line);
let (branch, _) = branch.context("failed to get name of current branch")?;
error[E0597]: `output.stdout` does not live long enough
--> src/status.rs:303:41
|
303 | let input = std::str::from_utf8(&output.stdout).unwrap();
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
307 | let branch: IResult<&str, &str> = tag("On branch ")(branch_line);
| ------------------- type annotation requires that `output.stdout` is borrowed for `'static`
...
436 | }
| - `output.stdout` dropped here while still borrowed
查看
anyhow
的文档,在我看来,它不应该在 &output.stdout
上引入任何生命周期限制。
fn context<C>(self, context: C) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
挠头。对一生来说还是新鲜事。
问题在于
branch
的类型,即IResult<&str, &str>
。
如果您查看实现,您可以看到这是
IResult<&str, &str, nom::error::Error<&str>>
的别名,这又是 Result<(&str, &str), nom::internal::err<nom::error::Error<&str>>>
的别名。
这看起来很复杂,但我想说的要点是
branch
是 Result
类型,并且 Err
的情况具有 nom::internal::err<nom::error::Error<&str>>
类型。换句话说,错误带有 &str
。
这是故意的,因为所有权对于 nom 来说是一个大问题。这与当前借用检查器的这些已知问题密切相关。 Nom 通过
Err
类型返还所有权来解决这个问题。
遗憾的是,这意味着它与
anyhow
不兼容。 nom
的错误类型旨在由 nom
使用,或者至少在提升到用户代码之前手动转换为其他内容。
解释您收到的确切错误:
output.stdout
是局部变量input
,以及其背后的其他所有内容,都引用了output.stdout
Err
的branch
变体仍在引用output.stdout
.context()
,或者更准确地说,它后面的 ?
,尝试从函数中返回 Err
变体,但失败了,因为它仍然引用 output.stdout
,并且该引用将比它的数据更长寿。参考资料。这对于
next().context()
来说不是问题,因为 None
的 next()
值确实 not 带有对 output.stdout
的引用。
解决此问题的一种方法是通过将
&str
从 Err
类型转换为拥有的 String
来破坏引用:
use anyhow::{Context, Result};
use nom::{bytes::complete::tag, IResult};
fn main() -> Result<()> {
let input = "aaaaaa".to_string();
let mut lines = input.lines();
let branch_line = lines.next().context("no output from `git status`")?;
let branch: IResult<&str, &str> = tag("On branch ")(branch_line);
let (branch, _) = branch
.map_err(|e| e.to_owned())
.context("failed to get name of current branch")?;
Ok(())
}