简体   繁体   English

迭代器通过引用返回项目,生命周期问题

[英]Iterator returning items by reference, lifetime issue

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 ?至少这条消息是什么意思:预期的具体生命周期,但发现绑定的生命周期参数

Note on the version of Rust used: at the time this question and answer were written, the Iterator trait used generics;注意所使用的 Rust 版本:在编写此问题和答案时, Iterator trait 使用泛型; 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>; }

In practical terms this affects nothing;实际上,这没有任何影响; it is merely that A becomes Self::Item .只是A变成了Self::Item

The definition of the Iterator trait is thus: Iterator trait 的定义是这样的:

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

Note carefully: fn next(&mut self) -> Option<A> .请注意: fn next(&mut self) -> Option<A>

Here is what you have:这是你所拥有的:

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

Note carefully: fn next<'a>(&'a mut self) -> Option<&'a u8> .请注意: fn next<'a>(&'a mut self) -> Option<&'a u8>

There are several problems here:这里有几个问题:

  1. You have introduced a new generic parameter <'a> which should not be there.您引入了一个新的通用参数<'a> ,它不应该在那里。 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 ρ₁.为方便起见并强调这里发生的事情,我将在 impl 块 ρ₀ 上定义的'a和在方法 ρ₁ 上定义的'a配音。 They are not the same.她们不一样。

  2. The lifetime of &mut self is different from that of the trait. &mut self的生命周期&mut self trait 的生命周期不同。

  3. 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 .返回类型的生命周期与 trait 不同:其中A&'ρ₀ u8 ,返回类型用于代替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.) (我不确定“绑定”位的确切含义,所以我会保持沉默,以免我错了。)

Here's what this amounts to: you cannot connect the lifetime of the object you are iterating over to &mut self .这就是它的含义:您无法将正在迭代的对象的生命周期连接到&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> .举个例子,迭代切片中的项目是通过创建一个连接到基本切片的新迭代器对象来完成的, 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.换句话说,迭代特征的设计方式不是,如果您正在生成引用,则返回self内部的某些内容,而是返回您引用的另一个对象内部的某些内容。

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, eg &'a [T] or even something like Items<'a, T> .对于您的特定的,大概是简单的示例,您应该停止产生引用,或者更改它,以便您的迭代器对象不包含您正在迭代的数据——让它只包含对它的引用,例如&'a [T]甚至像Items<'a, T>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM