使用PhantomData和unsafe处理流式迭代器作为普通迭代器

时间:2018-04-06 01:27:09

标签: stream iterator rust unsafe

我知道下面的代码是hacky,但它可以被称为安全和惯用Rust吗?有更好的方法吗?

// needs to do 'rustup default nightly' to run under valgrind
// #![feature(alloc_system, global_allocator, allocator_api)]
// extern crate alloc_system;
// use alloc_system::System;
// #[global_allocator]
// static A: System = System;

struct Foo<'a> {
    v: Vec<u8>,
    pos: usize,
    phantom: std::marker::PhantomData<&'a u8>,
}

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

    fn next(&mut self) -> Option<&'a mut u8> {
        let r = self.v.get_mut(self.pos);
        if r.is_some() {
            self.pos += 1;
            unsafe { Some(&mut *(r.unwrap() as *mut u8)) }
        } else {
            None
        }
    }
}

impl<'a> Foo<'a> {
    fn reset(&mut self) {
        self.pos = 0;
    }
}

fn main() {
    let mut x = Foo {
        v: (1..10).collect(),
        pos: 0,
        phantom: std::marker::PhantomData,
    };
    let vp = x.v.as_ptr();

    {
        for i in &mut x {
            println!("{}", i);
        }
    }
    {
        x.reset();
    }
    {
        for i in &mut x {
            *i *= *i;
        }
    }
    {
        x.reset();
    }
    {
        for i in &mut x {
            println!("{}", i);
        }
    }

    assert!(vp == x.v.as_ptr());
}

在评论中写一点,Valgrind告诉我没有泄漏,结果如预期的那样在Rust 1.26.0-nightly和1.25.0之间。

相关:

1 个答案:

答案 0 :(得分:2)

此代码不安全。该类型的用户可以选择任何生命周期,包括'static

fn constructor() -> Foo<'static> {
    Foo {
        v: vec![42; 10],
        pos: 0,
        phantom: std::marker::PhantomData,
    }
}

fn example() -> &'static u8 {
    let mut f = constructor();
    f.next().unwrap()
}

fn main() {
    println!("example: {}", example());
}

此处,example返回对不再在范围内的变量的引用,访问无效内存并破坏必须支持的限制。

在另一个Q&amp; A中,an example of how you could write this code没有unsafe