问题描述
在尝试解决 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) 混淆错误有关。