编写迭代器

时间:2014-12-22 10:45:22

标签: iterator rust

  

编者注:此代码示例来自1.0之前的Rust版本,并且不是有效的Rust 1.0代码。由于更改了for循环的实现方式,此代码的更新版本不再产生错误。

我在Rust中编写了一个Vector结构。

pub struct Vector {
    pub x: f32,
    pub y: f32,
    pub z: f32,

    curr: uint
}

我想为它编写一个简单的迭代器,以便我可以迭代向量的元素。它偶尔会有用,而且我对Rust中的迭代器几乎一无所知。

这就是我现在所拥有的。

impl Iterator<f32> for Vector {
    fn next(&mut self) -> Option<f32> {
        let new_next : Option<f32> = match self.curr {
            0 => Some(self.x),
            1 => Some(self.y),
            2 => Some(self.z), 
            _ => None
        };
        let new_curr = (self.curr + 1) % 4;
        mem::replace(&mut self.curr, new_curr);
        new_next
    }
}

现在理想情况下,我希望能够使用它:

let u = Vector::new(0.0f32, 0.0f32, 0.0f32);
for element in u {
    ///
}

但是,我收到以下编译器错误:

 error: cannot borrow immutable local variable `u` as mutable

所以我很难过。经过几个小时的谷歌搜索,我无法想出任何东西。我觉得我错过了一些巨大的东西。

2 个答案:

答案 0 :(得分:15)

您确定自己真的希望Vector 本身成为迭代器吗?通常,结构和迭代器是分开的。考虑这样的事情:

pub struct Vector {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

pub struct VectorIter<'a> {
    vector: &'a Vector,
    cur: usize,
}

impl<'a> Iterator for VectorIter<'a> {
    type Item = f32;

    fn next(&mut self) -> Option<f32> {
        let r = match self.cur {
            0 => self.vector.x,
            1 => self.vector.y,
            2 => self.vector.z,
            _ => return None,
        };
        self.cur += 1;
        Some(r)
    }
}

impl Vector {
    fn iter(&self) -> VectorIter {
        VectorIter {
            vector: self,
            cur: 0,
        }
    }
}

fn main() {
    let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
    for c in v.iter() {
        println!("{}", c);
    }
}

因为Vector非常简单,所以它可以派生Copy,并且它的迭代器可以通过值来获取它:

#[derive(Copy, Clone)]
pub struct Vector {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

pub struct VectorIter {
    vector: Vector,
    cur: usize,
}

impl Iterator for VectorIter {
    type Item = f32;
    fn next(&mut self) -> Option<f32> {
        let r = match self.cur {
            0 => self.vector.x,
            1 => self.vector.y,
            2 => self.vector.z,
            _ => return None,
        };
        self.cur += 1;
        Some(r)
    }
}

impl Vector {
    fn iter(&self) -> VectorIter {
        VectorIter {
            vector: *self,
            cur: 0,
        }
    }
}

fn main() {
    let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
    for c in v.iter() {
        println!("{}", c);
    }
}

除非您的Vector包含除坐标以外的内容,否则此变体可能更好。这个变体更灵活,因为它没有将迭代器与迭代相关联,但另一方面,正是由于同样的原因,它可能是不可取的(使用Copy你可以改变原始值,并且迭代器赢了& #39; t反映它;没有Copy和参考,你根本无法改变原始值。您想要大量使用的语义取决于您的用例。

答案 1 :(得分:4)

  

编者注:由于for循环的工作方式发生了变化,因此Rust 1.0的答案不再有用。

Vladimir Matveev的回答是正确的,并解释了你应该做些什么。我想通过更多地解释你的错误来补充。

  

错误:无法将不可变局部变量u作为可变

借用

当你在迭代某些东西时,你需要改变跟踪你所在位置的某些东西。在您的代码中,通过以下方式完成:

mem::replace(&mut self.curr, new_curr);

Rust知道你要改变哪个东西,因为next的方法签名表明它:

fn next(&mut self) -> Option<f32>

问题是您的对象不可变

let u = Vector::new(0.0f32, 0.0f32, 0.0f32);

如果您将代码更改为

let mut u = Vector::new(0.0f32, 0.0f32, 0.0f32);

我希望你的代码按原样运行。所有这一切,一个单独的迭代器可能是正确的方法。但是,您对代码的了解比我们更多!