我有一個帶有以下宣告的函式:
fn find_solutions_internal<'a, I>(&self, words: I, iterate_from: usize, chain: &mut Vec<u32>)
where I: Iterator<Item=&'a u32> Clone;
因為該函式使用不同的過濾器遞回迭代相同的向量(遞回的最大深度為 5),所以我決定將迭代器作為引數傳遞會更有效。
以下部分代碼導致錯誤:
let iterator = words.skip(iterate_from).filter(|&mask| mask & last_mask == 0);
let filtered_words = iterator.clone();
iterator.enumerate().for_each(|(i, &mask)| {
chain.push(mask);
self.find_solutions_internal(filtered_words.clone(), i, chain); // filtered_words.clone() is what indirectly causes the error
chain.pop();
});
錯誤:
error: reached the recursion limit while instantiating `<std::iter::Filter<std::iter::Sk...]>::{closure#0}]>::{closure#0}]>`
115 | self.iter.fold(init, fold)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `<std::iter::Filter<I, P> as Iterator>::fold` defined here
...
問題代碼的獨立示例:https ://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ada8578f166ad2a34373d82cc376921f
收集迭代到向量的作業示例:https ://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4c13d2d0ac17038dac61c9e2d59bbab5
uj5u.com熱心網友回復:
正如@Jmb 評論的那樣,編譯器不會嘗試計算函式遞回的次數,至少不是為了允許這種代碼編譯。編譯器假定每次呼叫find_solutions_internal()都可能遞回,因此編譯器在重復實體化函式時會卡住,因為每個遞回呼叫都有一個唯一的迭代器引數型別。
我們可以通過在進行遞回呼叫時將迭代器作為特征物件傳遞來解決此問題,盡管我們正在克隆迭代器的事實使事情變得復雜,因為Clone特征不適用于特征物件。我們可以用dyn_clonecrate 來解決這個問題,代價是一些樣板檔案。
首先我們定義一個可克隆的迭代器特征:
use dyn_clone::DynClone;
trait ClonableIterator<T>: Iterator<Item = T> DynClone {}
impl<I, T> ClonableIterator<T> for I where I: Iterator<Item = T> DynClone {}
dyn_clone::clone_trait_object!(<T> ClonableIterator<T>);
然后在遞回呼叫中我們構造 trait 物件:
self.find_solutions_internal(
Box::new(filtered_words.clone()) as Box<dyn ClonableIterator<_>>,
i,
chain,
);
雖然上述解決方案有效,但我認為它最終可能會比只收集到Vec. 如果向量真的很大,使用像Vector來自imcrate 的資料結構,它支持 O(1) 克隆和 O(log n) 洗掉可能會更快。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/520665.html
標籤:递归锈迭代器
