rust - Rust:错误[E0495]:由于闭包中的冲突要求,无法推断自动引用的适当生命周期
问题描述
原始想法
在我拥有的一个虚拟项目中,我想使用循环迭代器(例如生成整数)。
use std::iter::Cycle;
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let mut cycles = [
[1, 2].iter().cycle(),
[2, 4].iter().cycle(),
];
cycles
}
fn main() {
let mut cycles = generate_cycles();
// ...
}
重构
尽管前面的代码按预期工作,但我的真实示例有点复杂,所以我希望调整generate_cycles
函数以能够执行更多操作(在下面的示例中,乘以 2,然后生成循环迭代器)。为此,我尝试使用arraymap:
extern crate arraymap;
use arraymap::ArrayMap;
use std::iter::Cycle;
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let mut cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
points.iter().cycle()
})
}
fn main() {
let mut cycles = generate_cycles();
// ...
}
问题
上面的解决方案不起作用,而且,作为一个 Rust 初学者,最近接触了“生命周期”的概念,我不明白为什么编译器在这里抱怨,或者我能做些什么让他开心。
error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements
--> src/main.rs:20:14
|
20 | points.iter().cycle()
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 19:10...
--> src/main.rs:19:10
|
19 | .map(|points| {
| __________^
20 | | points.iter().cycle()
21 | | })
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:20:7
|
20 | points.iter().cycle()
| ^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected [std::iter::Cycle<std::slice::Iter<'static, i32>>; 2]
found [std::iter::Cycle<std::slice::Iter<'_, i32>>; 2]
这是一个 REPL,其代码试图使用arraymap
:https ://repl.it/repls/ShadowyStrikingFirm 。
解决方案
在您的类型声明中:
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
你说你用来构建迭代器的底层切片必须有'static
生命周期,也就是说,它们必须永远存在。然后你使用像这样的文字数组[1, 2]
,因为所有文字都有'static'
生命周期并且一切顺利:
let r: &'static [i32; 2] = &[1, 2]; //Ok
但是,您尝试使用类似于以下更简单的代码:
let a = [1, 2].map(|x| 2 * x);
let r: &'static [i32; 2] = &a; //error: borrowed value does not live long enough
那是arraymap::map
一个普通数组的结果,而不是文字数组,所以它没有'static
生命周期。它不能是静态的,因为您是在运行时计算值。只要有必要,它就会存在,在我的情况下,只要变量a
.
在您的情况下,由于arraymap::map
未将返回值分配给变量,因此它们是临时值,并且很快就会被删除。但是即使将它分配给局部变量,也无法返回对它的引用,因为局部变量在函数结束时被删除。
解决方案是返回一个拥有该值的迭代器。像这样的工作:
type IntegerCycle = Cycle<std::vec::IntoIter<i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
points.to_vec().into_iter().cycle()
})
}
不幸的是,您必须使用 aVec
而不是数组,因为没有IntoIterator
数组的实现(有切片,但它们不拥有值)。
如果你想避免额外的分配,Vec
你可以使用arrayvec
允许将迭代器带到数组的 crate:
type IntegerCycle = Cycle<arrayvec::IntoIter<[i32; 2]>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
let a = arrayvec::ArrayVec::from(*points);
a.into_iter().cycle()
})
}
注意:似乎有人尝试IntoIterator
按值向数组添加适当的 impl std
,但仍有一些悬而未决的问题。
推荐阅读
- php - 不显示我的参考链接
- python - 仅对时间序列中的某些数据点应用校正,这些数据点通过值快速下降来识别
- python - ValueError:输入数组应具有与目标数组相同数量的样本。找到 1600 个输入样本和 1800 个目标样本
- xml - ant 编译没有显示类
- c# - Unity:如何将 AssetBundle 构建到每个 AssetBundle 的单独目录中
- javascript - Discord.js 和 discord.js-commando 防止命令在特定通道中运行
- c# - 将 aspnet 核心作为服务运行 - nssm 与 RunAsService
- merge - SAS:合并具有不同名称的相同变量的两个数据集
- python - 操纵原始数据包以具有 NAT 功能
- json - 如何在swift 4中将数据附加到数组类型的JSON值