gpt4 book ai didi

rust - 如何返回具有多个生命周期的 impl Iterator?

转载 作者:行者123 更新时间:2023-11-29 08:17:28 25 4
gpt4 key购买 nike

我在 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))
}
}

( Playground )

这给我以下错误:

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 接受两个具有相同生命周期的引用参数。但是,我们通过借用具有不同生命周期的不同变量来调用它。那么为什么这段代码可以编译呢?

答案是subtyping and variance .较长的生命周期是较短生命周期的子类型;相反,较短的生命周期是较长生命周期的父类(super class)型。在上面的示例中,编译器必须找到一个与两个输入生命周期兼容的生命周期。编译器通过找到两个生命周期的公共(public)父类(super class)型(即包含两者的最短生命周期)来做到这一点。这称为统一


回到你的问题。好像是编译器doesn't handle multiple lifetime bounds on impl Trait too well眼下。然而,没有必要有两个生命周期界限:一个就足够了。如有必要,编译器将缩短此单个生命周期以满足 selfinput_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

关于rust - 如何返回具有多个生命周期的 impl Iterator?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58469240/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com