将 Box 与 nom 解析器一起使用时出现神秘错误“一种类型比另一种更通用”

问题描述

在尝试解决 today's Advent of Code 难题时,我尝试使用 nom 根据输入字符串构建一些动态解析器​​。但是在这样做时,我遇到了一个对我来说非常奇怪的问题,我对 Rust 缺乏熟悉(我正在使用代码的出现来尝试学习 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 否则编译器会抱怨在编译时不知道类型的大小。

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

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,)>`

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

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

解决方法

给定生命周期省略,那么您的 //public method to return an array list containing all keys,quickly ordered in descending order public static <K,V extends Comparable> ArrayList<K> fastSort(HashMap<K,V> results) { //create a new array list of type K to store the ordered key list in ArrayList<K> sortedUrls = new ArrayList<K>(); //insert all the keys of the specified hash map to the new list sortedUrls.addAll(results.keySet()); //call the quicksort method to sort the array list quicksort(sortedUrls,sortedUrls.size()-1); return sortedUrls; } private static <K,V extends Comparable> void swap(ArrayList<K> elements,int i,int j){ //Method to swap 2 elements in an arraylist K temp = elements.get(i); elements.set(i,elements.get(j)); elements.set(j,temp); } private static <K extends Comparable> void quicksort(ArrayList<K> elements,int beg,int end){ //make sure that beginning and end indexes are proper if(beg>=end) return; if(beg<0) return; if(end>elements.size()-1) return; //update the pivot and swap appropriate elements using the partition helper method int pivot = partition(elements,beg,end); //recursively call quicksort on either side of the pivot quicksort(elements,pivot-1); quicksort(elements,pivot+1,end); } private static <K extends Comparable> int partition(ArrayList<K> elements,int end){ //Get a random pivot between beg and end int random = beg + ((int)Math.random()*(elements.size()))/(end-beg+1); //New position of pivot element int last=end; //Move the pivot element to right edge of the array swap(elements,random,end); end--; while(beg<=end){ if(elements.get(beg).compareTo(elements.get(last)) < 0) beg++; //Accumulate smaller elements to the left else { swap(elements,end); end--; } } //Move pivot element to its correct position swap(elements,last); return beg; } 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

这与 issue (22340) "Can’t declare lifetime for closure that returns a reference" 和潜在的 issue (71723) 混淆错误有关。