Recursion 评估特性需求时堆栈溢出

Recursion 评估特性需求时堆栈溢出,recursion,rust,iterator,traits,Recursion,Rust,Iterator,Traits,我有一个函数,它对给定的项s上的任何迭代器进行可变引用。函数通常可以一个接一个地使用这些项,但有时必须执行前瞻。这样检索到的项有时会被使用,但有时必须“预先”返回到迭代器(例如使用链),然后该函数必须在迭代器上递归 但是,在解决trait需求时,执行会在运行时崩溃: error[E0275]:评估需求溢出`std::iter::Chain您的错误案例可以简化为: fn f(i:impl迭代器){ f(std::iter::once(()).chain(i))//解析为f(chain) } fn

我有一个函数,它对给定的
s上的任何迭代器进行可变引用。函数通常可以一个接一个地使用这些项,但有时必须执行前瞻。这样检索到的项有时会被使用,但有时必须“预先”返回到迭代器(例如使用
),然后该函数必须在迭代器上递归

但是,在解决trait需求时,执行会在运行时崩溃:


error[E0275]:评估需求溢出`std::iter::Chain您的错误案例可以简化为:

fn f(i:impl迭代器){
f(std::iter::once(()).chain(i))//解析为f(chain)
}
fn main(){
f(向量![]插入到iter()中)
}
这会导致错误:

overflow evaluating the requirement `std::iter::Chain<std::iter::Once<()>, std::iter::Chain<std::iter::Once<()>, ..>>
评估需求的溢出`std::iter::Chain
这是因为静态分派必须在编译时实例化。编译器可能会假设深度是,比方说,10,但如果达到深度11,应该执行什么呢?您已经提到的简单解决方案是通过trait对象进行动态调度,因为您的案例如下所示:

fn foo(it:&mut I)->String{
如果*(&1)==1{
字符串::new()
}否则{
让我们把它换成盒子=
Box::new(vec![String::new()])。into_iter().chain(it));
foo(&mut-it)//也可以使用'as-Box'进行适当的大小写`
}
}

另一种方法是用迭代代替递归(这也可能减少编译时间),正如@loganfsmyth所指出的,这可能非常适合您。此外,可能对这种情况也有帮助。

您的错误情况可能简化为:

fn f(i:impl迭代器){
f(std::iter::once(()).chain(i))//解析为f(chain)
}
fn main(){
f(向量![]插入到iter()中)
}
这会导致错误:

overflow evaluating the requirement `std::iter::Chain<std::iter::Once<()>, std::iter::Chain<std::iter::Once<()>, ..>>
评估需求的溢出`std::iter::Chain 这是因为静态分派必须在编译时实例化。编译器可能会假设深度是,比方说,10,但如果达到深度11,应该执行什么呢?您已经提到的简单解决方案是通过trait对象进行动态调度,因为您的案例如下所示:

fn foo(it:&mut I)->String{
如果*(&1)==1{
字符串::new()
}否则{
让我们把它换成盒子=
Box::new(vec![String::new()])。into_iter().chain(it));
foo(&mut-it)//也可以使用'as-Box'进行适当的大小写`
}
}

另一种方法是用迭代代替递归(这也可能减少编译时间),正如@loganfsmyth所指出的,这可能非常适合您。此外,对于这种情况也可能有帮助。

正如@Kitsu的回答所解释的,您当前的代码是有问题的,因为编译器无法计算递归的深度

如果您的基本要求是您的职能部门:

  • 从迭代器中获取一个或多个值
  • 根据某些逻辑,可以:
    • 返回结果,或
    • 将值放回迭代器,然后递归到自身
那么这可能是一个解决方案:

fn foo<I: Clone + Iterator<Item = String>>(mut it: I, n: i32) -> String {
    let mut start_iter = it.clone();
    let s = it.next();
    if n>4 {
        "Done".to_string()
    } else {
        foo(start_iter, n+1)
    }
}

fn main() {
    let mut it = ["apples", "bananas", "oranges", "mandarins", "peaches", "pears"].iter()
        .map(|s| s.to_string()).collect::<Vec<String>>().into_iter();
    println!["{:?}", foo(it, 0)];
}
fn-foo(mut-it:I,n:i32)->String{
让mut start_iter=it.clone();
让s=it.next();
如果n>4{
“完成”。to_string()
}否则{
foo(启动iter,n+1)
}
}
fn main(){
让我们用mut it=[“苹果”、“香蕉”、“橙子”、“柑橘”、“桃子”、“梨”]。iter()
.map(|s|s.to_string()).collect::()。to_iter();
println![“{:?}”,foo(it,0)];
}
我假设您必须有一些其他状态,允许函数确定何时停止递归-在我设计的示例中,我刚刚传递了一个额外的
i32
参数


请注意,迭代器的克隆成本通常很低(可能比构造链式迭代器,尤其是盒式迭代器要便宜得多)。

正如@Kitsu的回答所解释的,您当前的代码是有问题的,因为编译器无法计算递归的深度

如果您的基本要求是您的职能部门:

  • 从迭代器中获取一个或多个值
  • 根据某些逻辑,可以:
    • 返回结果,或
    • 将值放回迭代器,然后递归到自身
那么这可能是一个解决方案:

fn foo<I: Clone + Iterator<Item = String>>(mut it: I, n: i32) -> String {
    let mut start_iter = it.clone();
    let s = it.next();
    if n>4 {
        "Done".to_string()
    } else {
        foo(start_iter, n+1)
    }
}

fn main() {
    let mut it = ["apples", "bananas", "oranges", "mandarins", "peaches", "pears"].iter()
        .map(|s| s.to_string()).collect::<Vec<String>>().into_iter();
    println!["{:?}", foo(it, 0)];
}
fn-foo(mut-it:I,n:i32)->String{
让mut start_iter=it.clone();
让s=it.next();
如果n>4{
“完成”。to_string()
}否则{
foo(启动iter,n+1)
}
}
fn main(){
让我们用mut it=[“苹果”、“香蕉”、“橙子”、“柑橘”、“桃子”、“梨”]。iter()
.map(|s|s.to_string()).collect::()。to_iter();
println![“{:?}”,foo(it,0)];
}
我假设您必须有一些其他状态,允许函数确定何时停止递归-在我设计的示例中,我刚刚传递了一个额外的
i32
参数


请注意,迭代器的克隆成本通常很低(可能比构建链迭代器,尤其是盒装迭代器要便宜得多)。

如果不想从迭代器中删除条目,您是否研究过使用该方法?另请参见;另见;如果您不想删除迭代器中的条目,您是否已经研究过使用来避免删除该条目?另请参见;另见;谢谢Peekable是我想要的解决方案,因为我必须让更深层次的递归帧改变迭代器。谢谢。Peekable是我追求的解决方案,因为我必须让更深层次的递归帧改变迭代器。