我正在尝试实现我经常使用的
Vec.iter().map(...).collect()
模式的快捷方式。乍一看,并不难:
pub trait IterMap<T> {
fn mapcollect<F, U>(&self, f: F) -> Vec<U>
where
F: Fn(&T) -> U;
}
impl<T> IterMap<T> for Vec<T> {
fn mapcollect<F, U>(&self, f: F) -> Vec<U>
where
F: Fn(&T) -> U,
{
self.iter().map(f).collect()
}
}
对于简单的案例来说,它就像一个魅力:
let v = vec![5; 5];
let v_2 = v.mapcollect(|x| x * x);
但是,如果涉及生命周期,它就会崩溃:
let v: Vec<Vec<i32> = ...; // define 2D-vector here
let v_slice: Vec<&[i32]> = v.mapcollect(|x| x.as_slice());
原因是 Rust 无法通过我的
v_slice
抽象将 v
的生命周期与 mapcollect()
的生命周期联系起来。
当然,我可以使用适当的生命周期注释来实现另一个
mapcollect_with_lifetime(...)
,但这种方法有几个缺点。有没有办法帮助 Rust 自动计算出生命周期,就像原来的 iter().map(...).collect()
那样?
您根本不需要第二次实现,您可以使用单个正确实现的特征和实现来完成此操作。这是因为将生命周期添加到您的实现中是您如何帮助 rust 自动为调用者计算出这一点。
pub trait IterMap<'a, T: 'a> {
fn mapcollect<F, U>(&'a self, f: F) -> Vec<U>
where
F: Fn(&'a T) -> U,
U: 'a;
}
impl<'a, T: 'a> IterMap<'a, T> for Vec<T> {
fn mapcollect<F, U>(&'a self, f: F) -> Vec<U>
where
F: Fn(&'a T) -> U,
U: 'a,
{
self.iter().map(f).collect()
}
}
fn main() {
let v = vec![5; 5];
let v_2 = v.mapcollect(|x| x * x);
let v: Vec<Vec<i32>> = vec![vec![1, 2, 3], vec![4, 5, 6]];
let v_slice: Vec<&[i32]> = v.mapcollect(|x| x.as_slice());
}