迭代器通过引用返回项目,生命周期问题 [英] Iterator returning items by reference, lifetime issue

查看:15
本文介绍了迭代器通过引用返回项目,生命周期问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 lifetime 问题,我正在尝试实现一个通过引用返回其项目的迭代器,代码如下:

I have a lifetime issue, I'm trying to implement an iterator returning its items by reference, here is the code:

struct Foo {
   d: [u8; 42],
   pos: usize
}

impl<'a> Iterator<&'a u8> for Foo {
   fn next<'a>(&'a mut self) -> Option<&'a u8> {
      let r = self.d.get(self.pos);
      if r.is_some() {
         self.pos += 1;
      }
      r
   }
}

fn main() {
   let mut x = Foo {
      d: [1; 42],
      pos: 0
   };

   for i in x {
      println!("{}", i);
   }
}

但是这段代码没有正确编译,我遇到了一个与参数生命周期相关的问题,这是相应的错误:

However this code doesn't compile properly, I get an issue related to the lifetime of parameters, here is the corresponding error:

$ rustc test.rs
test.rs:8:5: 14:6 error: method `next` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter
test.rs:8     fn next<'a>(&'a mut self) -> Option<&'a u8> {
test.rs:9         let r = self.d.get(self.pos);
test.rs:10         if r.is_some() {
test.rs:11             self.pos += 1;
test.rs:12         }
test.rs:13         r
           ...
test.rs:8:49: 14:6 note: expected concrete lifetime is the lifetime 'a as defined on the block at 8:48
test.rs:8     fn next<'a>(&'a mut self) -> Option<&'a u8> {
test.rs:9         let r = self.d.get(self.pos);
test.rs:10         if r.is_some() {
test.rs:11             self.pos += 1;
test.rs:12         }
test.rs:13         r
           ...
error: aborting due to previous error

有人知道如何解决这个问题并仍然通过引用返回项目吗?

Does somebody has an idea how to fix this issue and still returning items by reference?

至少这个消息是什么意思:预期的具体生命周期,但找到绑定的生命周期参数?

At least what does this message means: expected concrete lifetime, but found bound lifetime parameter ?

推荐答案

关于所用 Rust 版本的注意事项: 在撰写此问题和答案时,Iterator trait 使用了泛型;它已更改为使用关联类型,现在定义如下:

Note on the version of Rust used: at the time this question and answer were written, the Iterator trait used generics; it has changed to use associated types and is now defined thus:

pub trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
    …
}

因此此处显示的错误实现如下所示:

And so the incorrect implementation shown here would be like this:

impl<'a> Iterator for Foo {
    type Item = &'a u8;

    fn next<'a>(&'a mut self) -> Option<&'a u8>;
}

实际上,这没有任何影响;只是A变成了Self::Item.

In practical terms this affects nothing; it is merely that A becomes Self::Item.

Iterator trait 的定义是这样的:

The definition of the Iterator trait is thus:

pub trait Iterator<A> {
    fn next(&mut self) -> Option<A>;
    …
}

注意:fn next(&mut self) ->选项.

这是你所拥有的:

impl<'a> Iterator<&'a u8> for Foo {
    fn next<'a>(&'a mut self) -> Option<&'a u8>;
}

注意:fn next<'a>(&'a mut self) ->选项<&'a u8>.

这里有几个问题:

  1. 您引入了一个新的通用参数 <'a>,它不应该存在.为方便起见并强调这里发生的事情,我将在 impl 块 ρ₀ 上定义的 'a 和在方法 ρ₁ 上定义的 'a 配音.它们不一样.

  1. You have introduced a new generic parameter <'a> which should not be there. For convenience’s sake and to emphasise what has happened here, I shall dub the 'a defined on the impl block ρ₀ and the 'a defined on the method ρ₁. They are not the same.

&mut self 的生命周期与 trait 的生命周期不同.

The lifetime of &mut self is different from that of the trait.

返回类型的生命周期与trait不同:其中A&'ρ₀ u8,返回类型用A &'ρ₁ u8.它预期的具体寿命为 ρ₀,但结果却是寿命 ρ₁.(我不确定确切地绑定"位是什么意思,所以我会保持沉默,以免我错了.)

The lifetime of the return type is different to the trait: where A is &'ρ₀ u8, the return type uses in the place of A &'ρ₁ u8. It expected the concrete lifetime ρ₀ but found instead the lifetime ρ₁. (I’m not certain precisely what the "bound" bit means, so I’ll keep quiet on it lest I be wrong.)

这意味着:您无法将正在迭代的对象的生命周期与 &mut self 联系起来.相反,它必须绑定到您正在为其实现特征的类型中的某些内容.举个例子,对切片中的项目进行迭代是通过创建一个连接到基本切片的新迭代器对象来完成的,impl<'a, T>迭代器<&'a T>对于项目<'a, T>.换句话说,迭代特征的设计方式不是,如果您正在生成引用,则返回 self 内部的某些内容,而是返回您引用的另一个对象内部的某些内容.

Here’s what this amounts to: you cannot connect the lifetime of the object you are iterating over to &mut self. Instead, it must be bound to something in the type you are implementing the trait for. To take an example, iterating over items in a slice is done by creating a new iterator object connected to the base slice, impl<'a, T> Iterator<&'a T> for Items<'a, T>. Expressed in another way, the way the iteration traits are designed is not, if you are producing references, for you to return something inside self, but rather to return something inside another object that you have a reference to.

对于您的具体的,大概是简单的示例,您应该停止产生引用,或者更改它,以便您的迭代器对象不包含您正在迭代的数据——让它只包含一个引用对它,例如&'a [T] 甚至类似 Items<'a, T>.

For your specific, presumably simple example, you should either stop yielding references, or alter it so that your iterator object does not contain the data that you are iterating over—let it merely contain a reference to it, e.g. &'a [T] or even something like Items<'a, T>.

这篇关于迭代器通过引用返回项目,生命周期问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆