Rust 可变迭代器问题 - 如何修复“无法推断适当的生命周期”错误?

问题描述

我在使用下面的代码时遇到问题。不可变迭代器工作正常,但可变迭代器给了我以下错误

无法为生命周期参数推断合适的生命周期 由于需求冲突导致的函数调用

是否有可能在不使用不安全的 Rust 和坚持迭代器特性的情况下以某种方式修复这个错误

游乐场链接https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ae0b3f4c5c7749b130fe0b0142beb9e7

代码

struct Collection<T,const S: usize> {
    data: Vec<T>
}

struct CollectionIterator<'a,T,const S: usize> {
    item_index: usize,collection: &'a Collection<T,S>
}

struct CollectionIteratorMut<'a,collection: &'a mut Collection<T,S>
}

impl<T: Clone,const S: usize> Collection<T,S> {
    fn new(num_items: usize,default_value: T) -> Collection<T,S> {
        Collection {
            data: vec![default_value; num_items * S]
        }
    }
    fn iter(&self) -> CollectionIterator<T,S> {
        CollectionIterator {
            item_index: 0,collection: self
        }
    }
    fn iter_mut(&mut self) -> CollectionIterator<T,collection: self
        }
    }
}

impl<'a,const S: usize> Iterator for CollectionIterator<'a,S> {
    type Item = &'a [T];
    fn next(&mut self) -> Option<Self::Item> {
        if self.item_index < self.collection.data.len() {
            self.item_index += S;
            Some(&self.collection.data[self.item_index - S .. self.item_index])
        } else {
            None
        }
    }
}

impl<'a,const S: usize> Iterator for CollectionIteratorMut<'a,S> {
    type Item = &'a mut [T];
    fn next(&mut self) -> Option<Self::Item> {
        if self.item_index < self.collection.data.len() {
            self.item_index += S;
            Some(&mut self.collection.data[self.item_index - S .. self.item_index])
        } else {
            None
        }
    }
}

fn main() {
    let mut c: Collection<f64,3> = Collection::new(5,0.0);
    for x in c.iter_mut() {
        x[0] = 100.0;
    }
    for x in c.iter() {
        println!("{} {} {}",x[0],x[1],x[2]);
    }
}

错误

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:52:23
   |
52 |             Some(&mut self.collection.data[self.item_index - S .. self.item_index])
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first,the lifetime cannot outlive the anonymous lifetime defined on the method body at 49:13...
  --> src/main.rs:49:13
   |
49 |     fn next(&mut self) -> Option<Self::Item> {
   |             ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:52:23
   |
52 |             Some(&mut self.collection.data[self.item_index - S .. self.item_index])
   |                       ^^^^^^^^^^^^^^^^^^^^
note: but,the lifetime must be valid for the lifetime `'a` as defined on the impl at 47:6...
  --> src/main.rs:47:6
   |
47 | impl<'a,S> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:49:46
   |
49 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
50 | |         if self.item_index < self.collection.data.len() {
51 | |             self.item_index += S;
52 | |             Some(&mut self.collection.data[self.item_index - S .. self.item_index])
...  |
55 | |         }
56 | |     }
   | |_____^
   = note: expected `Iterator`
              found `Iterator`

解决方法

    fn next(&mut self) -> Option<Self::Item> {
        if self.item_index < self.collection.data.len() {
            self.item_index += S;
            Some(&mut self.collection.data[self.item_index - S .. self.item_index])
        } else {
            None
        }
    }

您编写的代码将生成一系列对 self.collection 不同部分的可变引用。但是编译器(借用检查器)不会对索引算法进行任何分析来确定它们实际上是不重叠的。因此,此代码被拒绝。一般来说,如果没有不安全的代码,就无法编写向集合中生成可变引用的迭代器,因为借用检查器理解的唯一一种非重叠引用是不同的结构/元组字段。

但是,您不需要编写不安全的代码来解决这个特定问题,因为 std::slice::ChunksMut 返回的迭代器 <[T]>::chunks_mut 已经包含您需要的实现。非可变 chunks() 也可以替换您的其他迭代器实现。

impl<T: Clone,const S: usize> Collection<T,S> {
    fn new(num_items: usize,default_value: T) -> Collection<T,S> {
        Collection {
            data: vec![default_value; num_items * S]
        }
    }
    fn iter(&self) -> impl Iterator<Item = &[T]> + '_ {
        self.data.chunks(S)
    }
    fn iter_mut(&mut self) -> impl Iterator<Item = &mut [T]> + '_ {
        self.data.chunks_mut(S)
    }
}