首页 > 解决方案 > 使用 transmute 实现可变迭代器以避免与不可变对应物的代码重复是否安全?

问题描述

Vec我有一个自定义迭代器,它以非连续方式从对 a 的引用中读取数据。它永远不会返回对同一内存的两个引用,所以我相信实现一个可变的对应物是安全的。

然而,迭代器本身的逻辑是相当复杂的,对于可变版本来说它是完全一样的。为了避免代码重复,我在底层使用我的非 mut 迭代器,然后转换结果以增加可变性。这按预期工作,但我不确定它是否在调用某种未定义的行为。

pub mod lib {
    pub struct Data {
        pub v: Vec<u64>,
    }

    impl Data {
        pub fn iter(&self) -> MyIter {
            MyIter {
                data: &self.v,
                i: 0,
            }
        }

        pub fn iter_mut(&mut self) -> MyIterMut {
            MyIterMut { iter: self.iter() }
        }
    }

    pub struct MyIter<'a> {
        data: &'a [u64],
        i: usize,
    }

    impl<'a> Iterator for MyIter<'a> {
        type Item = &'a u64;

        fn next(&mut self) -> Option<Self::Item> {
            if self.i == self.data.len() {
                return None;
            }
            let res = &self.data[self.i];
            self.i += 1;
            Some(res)
        }
    }

    pub struct MyIterMut<'a> {
        iter: MyIter<'a>,
    }

    impl<'a> Iterator for MyIterMut<'a> {
        type Item = &'a mut u64;

        fn next(&mut self) -> Option<Self::Item> {
            unsafe { std::mem::transmute(self.iter.next()) }
        }
    }
}

fn main() {
    let mut d = lib::Data { v: vec![0; 8] };

    for elem in d.iter_mut() {
        *elem = 123;
    }

    println!("{:?}", d.v);
}

完整的工作示例

可变迭代器仅在iter_mut方法中构造。这意味着初始值将始终作为可变变量开始,因为&mut self. 不可能从不可变变量构造这个可变迭代器。

在 C++ 中,您通常会使用 aconst_cast来避免重复仅在 constness 上有所不同的实现。

这是我可以在 Rust 中做的事情吗?

标签: rustiterator

解决方案


如果MyIter包含对原始 vec 的不可变引用,则不能转换,因为您可能有多个 的实例MyIter,从而导致引用冲突。似乎duplicatecrate 可以在这里使用,它提供了一种复制代码的简单方法,但略有不同。


推荐阅读