迭代器

我们在讲代码控制流那章节时,没有讲for 的使用,因为RUST 对于for 是 作为语法糖解释的 其中会用到迭代器特征

迭代器特征

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;

    //省略了其他大量的默认方法
}

直观看这个特征的定义,该特征可以从一个 实现了该特征的类型上,通过next 的方法, 得到一个 Item自定义类型的值

下面是基于迭代器上面,对于for的进一步说明

struct Collec {
    start: u32,
    end:u32,
    current:u32,
}

impl Iterator for Collec {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current <  self.start {
            self.current = self.start;
            Some(self.current)
        } else if self.current < self.end {
            self.current+=1;
            Some(self.current)
        } else {
           return None;
        }


    }

}

impl Collec {
    fn new(start:u32, end:u32) -> Collec {
         Collec {start, end, current:0}
    }
}

fn main() {
    let c = Collec::new(1, 20);

    for i in c {
        println!("{}",i);
    }
}

如果 遍历一个迭代器,RUST 会对for 进行展开

fn main() {
    let c = Collec::new(1, 20);

    while let Some(i) = c.next() {
         println!("{}",i);
    }
}

类型和迭代器的转换

上面我们举得例子,Collec 自身就是一个迭代器,实际编程中,我们更多会对希望迭代的对象 生成一个新的迭代器类型

一般约定,从一个类型到 迭代器类型,原类型可以通过三种方法实现

  • iter(&self): 该方法通过原类型的不可变引用,返回一个迭代器,迭代器得到的是内部元素的引用
  • iter_mut(&mut self): 该方法,可以获取内部元素的可变引用
  • into_iter(self): 该方法可以获得内部值的元素所有权,同时会消耗掉原类型 原类型不可以使用
pub trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;

    // Required method
    fn into_iter(self) -> Self::IntoIter;
}

如果for 语法糖中的类型实现了IntoIterator, RUST 会尝试对语法糖解包


fn main() {
    for i in 0..20 {
        println!("{}",i);
    }
    //0..20 其实是一个语法糖,实际是定义了一个Range类型 该类型还有很多其他变体
    assert_eq!((0..20), std::ops::Range { start: 0, end: 20 })
}

fn main() {
    let mut ranage = std::ops::Range { start: 0, end: 20 };
    {
        let result = match IntoIterator::into_iter(ranage) {
            mut iter => loop {
                let next;
                match iter.next() {
                    Some(val) => next = val,
                    None => break,
                };
                let i = next;
                let () = { println!("{i}"); };
            },
        };
        result
    }
}