在递归函数中链接本地迭代器时出现 Rust 生命周期问题
Rust Lifetime issue when chaining local iterator in recursive function
我有一个通用函数,它被递归调用并且可以接受可以转换为迭代器的参数。
我想将作为参数传递的迭代器与从函数本地集合创建的迭代器链接起来。这个想法是,在多次调用递归函数之后,将创建一个迭代器,该迭代器能够迭代位于其各自堆栈框架中的所有集合。
fn func_taking_iter<'a, I>(vals: I) -> ()
where
I: IntoIterator<Item = &'a u32>,
I::IntoIter: Clone,
{
let vals = vals.into_iter();
let mut new_val: [u32; 1] = [0u32; 1];
for x in vals.clone() {
new_val[0] = *x;
}
new_val[0] += 1u32;
if new_val[0] == 10u32 {
for x in vals {
println!("Value {}", *x);
}
return;
}
let res = vals.into_iter().chain(new_val.into_iter());
func_taking_iter(res);
}
fn main() {
let first_val = [0u32; 1];
func_taking_iter(first_val.iter());
}
不幸的是,当我尝试编译代码时出现以下错误。
error[E0597]: `new_val` does not live long enough
--> src\main.rs:20:38
|
1 | fn func_taking_iter<'a, I>(vals: I) -> ()
| -- lifetime `'a` defined here
...
20 | let res = vals.into_iter().chain(new_val.into_iter());
| -----------------------^^^^^^^-------------
| | |
| | borrowed value does not live long enough
| argument requires that `new_val` is borrowed for `'a`
...
23 | }
| - `new_val` dropped here while still borrowed
我对 Rust 没有那么多经验,我被困在这里,但在我看来,这似乎不是一件不可能的事情...
编辑:由于 Stargateur
中的提示,改进了示例代码以便仅克隆迭代器而不是整个集合
您将新数组的生命周期绑定到函数之外的生命周期'a
,这是生命周期系统的限制我认为您今天无法修复它,也许在未来会编译。但即使您可以解决生命周期问题,您最终也会得到 "overflow evaluating the requirement" (E0275])。编译器需要推断出无限多的函数,因为这个函数有无限次调用,无限链式结构。
我不建议在 Rust 中编写这种代码,链接这么多迭代器效率不高。我认为您应该更改代码以使用向量。这将节省您的堆栈 space 因为无论如何您的函数不是尾递归的所以您可能会以堆栈溢出问题结束。
fn func_taking_iter_aux(vals: Vec<u32>) -> Vec<u32> {
let new_val = vals.last().copied().unwrap_or(0) + 1;
if new_val == 10u32 {
vals
} else {
let mut vals = vals;
vals.push(new_val);
func_taking_iter_aux(vals)
}
}
fn func_taking_iter<'a, I>(vals: I) -> Vec<u32>
where
I: IntoIterator<Item = &'a u32>,
{
func_taking_iter_aux(vals.into_iter().copied().collect())
}
fn main() {
let vals = func_taking_iter(Some(&0));
for x in vals {
println!("Value {}", x);
}
}
我尽量满足你的要求。这现在是一个尾递归函数。
请注意,在您的代码中 vals.clone()
克隆所有数据而不仅仅是迭代器,您应该执行 let vals = vals.into_iter()
然后您可以克隆迭代器,当然也可以删除 I: Clone,
。
我有一个通用函数,它被递归调用并且可以接受可以转换为迭代器的参数。
我想将作为参数传递的迭代器与从函数本地集合创建的迭代器链接起来。这个想法是,在多次调用递归函数之后,将创建一个迭代器,该迭代器能够迭代位于其各自堆栈框架中的所有集合。
fn func_taking_iter<'a, I>(vals: I) -> ()
where
I: IntoIterator<Item = &'a u32>,
I::IntoIter: Clone,
{
let vals = vals.into_iter();
let mut new_val: [u32; 1] = [0u32; 1];
for x in vals.clone() {
new_val[0] = *x;
}
new_val[0] += 1u32;
if new_val[0] == 10u32 {
for x in vals {
println!("Value {}", *x);
}
return;
}
let res = vals.into_iter().chain(new_val.into_iter());
func_taking_iter(res);
}
fn main() {
let first_val = [0u32; 1];
func_taking_iter(first_val.iter());
}
不幸的是,当我尝试编译代码时出现以下错误。
error[E0597]: `new_val` does not live long enough
--> src\main.rs:20:38
|
1 | fn func_taking_iter<'a, I>(vals: I) -> ()
| -- lifetime `'a` defined here
...
20 | let res = vals.into_iter().chain(new_val.into_iter());
| -----------------------^^^^^^^-------------
| | |
| | borrowed value does not live long enough
| argument requires that `new_val` is borrowed for `'a`
...
23 | }
| - `new_val` dropped here while still borrowed
我对 Rust 没有那么多经验,我被困在这里,但在我看来,这似乎不是一件不可能的事情...
编辑:由于 Stargateur
您将新数组的生命周期绑定到函数之外的生命周期'a
,这是生命周期系统的限制我认为您今天无法修复它,也许在未来会编译。但即使您可以解决生命周期问题,您最终也会得到 "overflow evaluating the requirement" (E0275])。编译器需要推断出无限多的函数,因为这个函数有无限次调用,无限链式结构。
我不建议在 Rust 中编写这种代码,链接这么多迭代器效率不高。我认为您应该更改代码以使用向量。这将节省您的堆栈 space 因为无论如何您的函数不是尾递归的所以您可能会以堆栈溢出问题结束。
fn func_taking_iter_aux(vals: Vec<u32>) -> Vec<u32> {
let new_val = vals.last().copied().unwrap_or(0) + 1;
if new_val == 10u32 {
vals
} else {
let mut vals = vals;
vals.push(new_val);
func_taking_iter_aux(vals)
}
}
fn func_taking_iter<'a, I>(vals: I) -> Vec<u32>
where
I: IntoIterator<Item = &'a u32>,
{
func_taking_iter_aux(vals.into_iter().copied().collect())
}
fn main() {
let vals = func_taking_iter(Some(&0));
for x in vals {
println!("Value {}", x);
}
}
我尽量满足你的要求。这现在是一个尾递归函数。
请注意,在您的代码中 vals.clone()
克隆所有数据而不仅仅是迭代器,您应该执行 let vals = vals.into_iter()
然后您可以克隆迭代器,当然也可以删除 I: Clone,
。