我在impl特质上的一生中遇到麻烦。我正在尝试使以下代码工作:
struct Foo<'op, Input> {
op: Box<dyn Fn(Input) -> i32 + 'op>,
}
impl<'op, Input> Foo<'op, Input> {
fn new<Op>(op: Op) -> Foo<'op, Input>
where
Op: Fn(Input) -> i32 + 'op,
{
Foo { op: Box::new(op) }
}
fn apply<'input_iter, InputIter>(
self,
input_iter: InputIter,
) -> impl Iterator<Item = i32> + 'op + 'input_iter
where
InputIter: IntoIterator<Item = Input> + 'input_iter,
{
input_iter.into_iter().map(move |input| (self.op)(input))
}
}
(操场)
这给了我以下错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:20:36
|
20 | input_iter.into_iter().map(move |input| (self.op)(input))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'op as defined on the impl at 5:6...
--> src/lib.rs:5:6
|
5 | impl<'op, Input> Foo<'op, Input> {
| ^^^
= note: ...so that the types are compatible:
expected Foo<'_, _>
found Foo<'op, _>
note: but, the lifetime must be valid for the lifetime 'input_iter as defined on the method body at 13:14...
--> src/lib.rs:13:14
|
13 | fn apply<'input_iter, InputIter>(
| ^^^^^^^^^^^
note: ...so that return value is valid for the call
--> src/lib.rs:16:10
|
16 | ) -> impl Iterator<Item = i32> + 'op + 'input_iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
这是我对所涉及生命的理解。Foo拥有一个op,这是一个闭包,可能在其中某个地方有一个引用,因此它可能有一定的寿命。这用'op表示,并且Foo受约束以致无法生存。到现在为止还挺好。
在apply()中,想法是我们要消耗一个input_iter和self并返回使用self.op映射的input_iter中每个元素的迭代器。input_iterator也可能包含引用,因此它可能具有自己的生命周期界限,以'input_iter表示。
我想要的是返回一个同时拥有self和input_iter所有权的迭代器。这样做时,必须同时使用它们的生命周期参数,以确保它不超过input_iter引用或op引用。我以为impl Iterator<Item = i32> + 'op + 'input_iter
可以做到这一点,但我似乎在某个地方走错了路。
它抱怨关闭也很奇怪。我知道闭包不能超过'op,因为它需要拥有运算符及其引用的所有权。这是很合理的。我不明白的是为什么它需要活到'input_iter一样长。闭包和输入迭代器根本不应该在意彼此。连接它们的唯一一件事是它们都具有相同的所有者(输出迭代器)。
我在这里想念什么?
生命周期参数并不总是代表对象(或借用)的确切生命周期。让我们考虑这个例子:
fn main() {
let a = 3;
let b = 5;
let c = min(&a, &b);
println!("{:?}", c);
}
fn min<'a>(a: &'a i32, b: &'a i32) -> &'a i32 {
if a < b {
a
} else {
b
}
}
在这里,min
采用两个具有相同生存期的参考参数。但是,我们称其为借用具有不同生存期的不同变量。那么为什么要编译此代码?
答案是分型和差异。较大的寿命是亚型寿命较短的; 相反,较短的寿命是较大寿命的超类型。在上面的示例中,编译器必须找到一个与两个输入生存期都兼容的生存期。编译器通过找到两个生命周期的通用超类型(即包含这两个生命周期的最短生命周期)来完成此任务。这称为统一。
回到你的问题。这似乎是编译器不会在处理多个生命周期界限impl Trait
非常清楚的时刻。但是,并不需要两个生命周期界限:一个就足够了。编译器将缩短该单个寿命如果需要同时满足的要求self
和input_iter
。
struct Foo<'op, Input> {
op: Box<dyn Fn(Input) -> i32 + 'op>,
}
impl<'op, Input> Foo<'op, Input> {
fn new<Op>(op: Op) -> Foo<'op, Input>
where
Op: Fn(Input) -> i32 + 'op,
{
Foo { op: Box::new(op) }
}
fn apply<InputIter>(
self,
input_iter: InputIter,
) -> impl Iterator<Item = i32> + 'op
where
Input: 'op,
InputIter: IntoIterator<Item = Input> + 'op,
{
input_iter.into_iter().map(move |input| (self.op)(input))
}
}
fn main() {
let y = 1;
let foo = Foo::new(|x| x as i32 + y);
let s = "abc".to_string();
let sr: &str = &*s;
let bar = sr.chars();
let baz: Vec<_> = foo.apply(bar).collect();
println!("{:?}", baz);
}
尝试main
四处移动线条,以使自己确信生命周期确实是统一的。
在这一点上,调用生命周期'op
有些误导。它也可能被称为'a
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句