LoginSignup
6
7

More than 5 years have passed since last update.

rustのiteratorのメモ

Last updated at Posted at 2019-02-15

まずは、空のtypeと付随するiteratorを作ってみる

struct A {}
struct AIter {
    now: usize,
}
impl A {
    fn new() -> A {
        A {}
    }

    fn iter(&self) -> AIter {
        AIter { now: 0 }
    }
}

impl Iterator for AIter {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        self.now += 1;
        Some(self.now - 1)
    }
}

fn main() {
    let a = A::new();
    assert_eq!(
        vec![0, 1, 2, 3, 4],
        a.iter().take(5).collect::<Vec<usize>>()
    );
}

playground
特につまるところはなし。iterの引数には&つけないと、iter()よぶとmoveされてしまう。

次にAにVecを足してその値をiteratorでとりだせるようにしてみる

struct A {
    v: Vec<i32>,
}
struct AIter<'a> {
    a: &'a A,
    now: usize,
}
impl A {
    fn new(v: Vec<i32>) -> A {
        A { v: v }
    }

    fn iter(&self) -> AIter {
        AIter { a: &self, now: 0 }
    }
}

impl<'a> Iterator for AIter<'a> {
    type Item = i32;
    fn next(&mut self) -> Option<i32> {
        self.now += 1;
        if self.now - 1 < self.a.v.len() {
            Some(self.a.v[self.now - 1])
        } else {
            None
        }
    }
}

fn main() {
    let a = A::new(vec![6, 7, 8, 9, 10, 11, 12]);
    assert_eq!(vec![6, 7, 8, 9, 10], a.iter().take(5).collect::<Vec<i32>>());
}

playground
Iteratorの中にreferenceをもたせてその値を使用する。

もう少しややこしくして、Vec<String>にしつつ、&strをiteratorでとりだせるようにする。

struct A {
    v: Vec<String>,
}
struct AIter<'a> {
    a: &'a A,
    now: usize,
}
impl A {
    fn new(v: Vec<&str>) -> A {
        A {
            v: v.iter().map(|s| s.to_string()).collect(),
        }
    }

    fn iter(&self) -> AIter {
        AIter { a: &self, now: 0 }
    }
}

impl<'a> Iterator for AIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        self.now += 1;
        if self.now - 1 < self.a.v.len() {
            Some(&self.a.v[self.now - 1])
        } else {
            None
        }
    }
}

fn main() {
    let a = A::new(vec!["a", "b", "c", "d", "e", "f", "g"]);
    assert_eq!(
        vec!["a", "b", "c", "d", "e"],
        a.iter().take(5).collect::<Vec<&str>>()
    );

}

playground
Vec<i32>Vec<String>にしてOption<i32>Option<&str>にする
Stringと&strのあたりはあまり自信なし

ここからが本題。2種類のIteratorをつくってtake(5)を関数にしてみる

struct A {
    v: Vec<String>,
}
struct AIter<'a> {
    a: &'a A,
    now: usize,
}
struct AIter2 {
    now: usize,
}
impl A {
    fn new(v: Vec<&str>) -> A {
        A {
            v: v.iter().map(|s| s.to_string()).collect(),
        }
    }

    fn iter(&self) -> AIter {
        AIter { a: &self, now: 0 }
    }
    fn iter2(&self) -> AIter2 {
        AIter2 { now: 0 }
    }
}

impl<'a> Iterator for AIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        self.now += 1;
        if self.now - 1 < self.a.v.len() {
            Some(&self.a.v[self.now - 1])
        } else {
            None
        }
    }
}
impl Iterator for AIter2 {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        self.now += 1;
        Some(self.now - 1)
    }
}

fn take5<T, I : Iterator<Item = T>>(iter: I) -> Vec<T> {
    iter.take(5).collect()
}

//fn take5<T>(iter: impl Iterator<Item = T>) -> Vec<T> {
//    iter.take(5).collect()
//}

fn main() {
    let a = A::new(vec!["a", "b", "c", "d", "e", "f", "g"]);
    assert_eq!(vec!["a", "b", "c", "d", "e"], take5(a.iter()));
    assert_eq!(vec![0, 1, 2, 3, 4], take5(a.iter2()));
}

playground
genericsとimpl Traitをつかう。impl Traitがない時代はどうしてたのかは不明。こういう場合には、IntoIteratorは使えない。
impl Traitを使う必要はない。

assert_eq!はやめて、take5の中でforでprintln!するようにしてみる。以下は抜粋

fn take5<T: std::fmt::Display>(iter: impl Iterator<Item = T>) {
    for i in iter.take(5) {
        println!("{}", i);
    }
}

fn main() {
    let a = A::new(vec!["a", "b", "c", "d", "e", "f", "g"]);
    take5(a.iter());
    take5(a.iter2());
}

playground

6
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7