1

在尝试解决今天的代码出现难题时,我正在尝试使用 nom 来构建一些取决于输入字符串的动态解析器​​。但是在这样做的过程中,我遇到了一个对我来说非常特殊的问题,我对 Rust 缺乏熟悉(我正在使用 Advent of Code 来尝试学习 Rust,从未使用过它,或者任何其他“低级“以前的语言)使我无法解决。

以下是一个超级简化的示例,如果它编译,显然不会做任何有用的事情 - 但它说明了编译器错误(遗憾的是我不能把它放在 Rust Playground 上,因为它没有可用的 nom,但它可以很容易地独立运行):

use nom::IResult;

type MyParser = Box<dyn Fn(&str) -> IResult<&str, ()>>;

fn build_parser() -> MyParser {
    let parser = |_| Ok(("", ()));
    Box::new(parser)
}

fn main() {
    let parser = build_parser();
    let result = parser("some dummy text");
    println!("result was {:?}", result);
}

Box 是必需的,否则编译器会抱怨在编译时不知道类型的大小。

这失败了,出现了 2 个非常相似的错误Box::new(尽管请注意,在我的真实代码中只发生了其中的第二个),两者都抱怨实际上相同的不匹配类型:

mismatched types

one type is more general than the other

note: expected enum `std::result::Result<(&str, ()), nom::Err<nom::error::Error<&str>>>`
         found enum `std::result::Result<(&str, ()), nom::Err<nom::error::Error<&str>>>`

mismatched types

one type is more general than the other

note: expected type `std::ops::FnOnce<(&str,)>`
         found type `std::ops::FnOnce<(&str,)>`

注意:我在谷歌上搜索并遇到了许多关于类似错误的问题 - 其中似乎是最有希望的,但该答案或我发现的其他讨论中没有任何线索让我知道我的情况可能发生了什么。我已经尝试了很多更改,但到目前为止没有任何效果,而且我觉得我只是在挣扎,不了解导致此错误的原因。

任何见解将不胜感激,它可以解决上述问题而不会彻底改变它。

4

1 回答 1

3

给定终身省略,那么你MyParser Fn的解释为:

Fn(&'a str) -> IResult<&'a str, ()>

但是,编译器将闭包的返回类型解释为&'static str

Fn(&str) -> IResult<&'static str, ()>

从而导致“不匹配类型”错误。


您可以通过显式定义生命周期来解决此问题。

type MyParser<'a> = Box<dyn Fn(&'a str) -> IResult<&'a str, ()>>;

fn build_parser<'a>() -> MyParser<'a> {
    let parser = |_| Ok(("", ()));
    Box::new(parser)
}

另外,你不需要使用Box你可以使用impl Fn.

fn build_parser<'a>() -> impl Fn(&'a str) -> IResult<&'a str, ()> {
    let parser = |_| Ok(("", ()));
    parser
}

这与问题 (22340) “无法声明返回引用的闭包的生命周期”有关,并可能导致混淆错误的问题 (71723)

于 2020-12-19T14:19:50.797 回答