Rust 如何实现产生可变引用的迭代器

Rust 如何实现产生可变引用的迭代器,rust,Rust,我正在尝试实现一个简单的查找迭代器: LookupIterMut选项的发布结构LookupIterMut迭代器{ 如果self.i>=self.index.len(){ 没有一个 }否则{ 使用index=self.index[self.i]; 自我评价i+=1; Some(&mut self.data[index])//此处出错 } } } 其思想是允许调用者连续可变地访问内部存储器。但是,由于需求冲突,我得到了错误无法为函数调用中的生存期参数推断适当的生存期 据我所知,我必须将函数签名更改

我正在尝试实现一个简单的查找迭代器:

LookupIterMut选项的发布结构LookupIterMut迭代器{ 如果self.i>=self.index.len(){ 没有一个 }否则{ 使用index=self.index[self.i]; 自我评价i+=1; Some(&mut self.data[index])//此处出错 } } } 其思想是允许调用者连续可变地访问内部存储器。但是,由于需求冲突,我得到了错误
无法为函数调用中的生存期参数推断适当的生存期

据我所知,我必须将函数签名更改为
next(&'a mut self)->…
,但这将不再是迭代器

我还发现,我可以简单地使用原始指针,尽管我不确定这是否适合这里:

/。。。
类型项=*mut D;
// ...

感谢您的帮助

您的代码无效,因为您试图以相同的生存期将多个可变引用返回到同一个片段
'a

要使这样的事情起作用,您需要为每个返回的
使用不同的生存期,这样您就不会持有对同一个切片的两个可变引用。您目前无法执行此操作,因为它需要泛型关联类型:

type Item<'item> = &'item mut D; // Does not work today
请注意,如果一个索引超出范围,您的代码将死机。

使用
safe
提醒:在任何时候,对同一基础值有两个可访问的可变引用都是不合理的

问题的关键在于,语言无法保证代码遵守上述规则,如果
索引
包含任何重复项,那么实现的迭代器将允许同时获得对切片中相同项的两个可变引用,这是不合理的

如果语言本身无法提供担保,则您需要找到替代方法,或者进行尽职调查,然后使用
不安全的

在这种情况下,在:

impl{
发布fn新(数据:&'a mut[D],索引:&'a[usize])->Self{
let set:HashSet=index.iter().copied().collect();
断言!(index.len()==set.len(),“重复索引!”);
自{数据,索引,i:0}
}
}
恳求{
类型项=&'a mut D;
fn下一步(&mut self)->选项{
如果self.i>=self.index.len(){
没有一个
}否则{
设index=self.index[self.i];
断言!(索引

就性能而言,在构造函数中构造
HashSet
是相当不令人满意的,但通常不能真正避免。例如,如果保证对
索引进行排序,则可以在不分配的情况下执行检查。

我还简化了
下一步的方法。
mod my_mod {
    pub struct LookupIterMut<'a, D> {
        data: &'a mut [D],
        indices: &'a [usize],
        i: usize,
    }

    impl<'a, D> LookupIterMut<'a, D> {
        pub fn new(data: &'a mut [D], indices: &'a [usize]) -> Result<Self, ()> {
            let mut uniq = std::collections::HashSet::new();
            let all_distinct = indices.iter().all(move |&x| uniq.insert(x));

            if all_distinct {
                Ok(LookupIterMut {
                    data,
                    indices,
                    i: 0,
                })
            } else {
                Err(())
            }
        }
    }

    impl<'a, D> Iterator for LookupIterMut<'a, D> {
        type Item = &'a mut D;

        fn next(&mut self) -> Option<Self::Item> {
            self.indices.get(self.i).map(|&index| {
                self.i += 1;

                unsafe { std::mem::transmute(&mut self.data[index]) }
            })
        }
    }
}
impl<'a, D> LookupIterMut<'a, D> {
    pub fn new(data: &'a mut [D], indices: &'a [usize]) -> Self {
        let set: HashSet<usize> = indices.iter().copied().collect();
        assert!(indices.len() == set.len(), "Duplicate indices!");

        Self { data, indices, i: 0 }
    }
}

impl<'a, D> Iterator for LookupIterMut<'a, D> {
    type Item = &'a mut D;

    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.indices.len() {
            None
        } else {
            let index = self.indices[self.i];
            assert!(index < self.data.len());

            self.i += 1;

            //  Safety:
            //  -   index is guaranteed to be within bounds.
            //  -   indices is guaranteed not to contain duplicates.
            Some(unsafe { &mut *self.data.as_mut_ptr().offset(index as isize) })
        }
    }
}