Lazy sequence generation in Rust

前端 未结 4 2065
梦毁少年i
梦毁少年i 2020-12-05 04:20

How can I create what other languages call a lazy sequence or a \"generator\" function?

In Python, I can use yield as in the following example (from Pyt

4条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-05 04:53

    As of Rust 1.34 stable, you have convenient std::iter::from_fn utility. It is not a coroutine (i.e. you still have to return each time), but at least it saves you from defining another struct.

    from_fn accepts a closure FnMut() -> Option and repeatedly calls it to create an Iterator.

    // -> Box> in Rust 2015
    fn firstn(n: u64) -> impl std::iter::Iterator {
        let mut num = 0;
        std::iter::from_fn(move || {
            let result;
            if num < n {
                result = Some(num);
                num += 1
            } else {
                result = None
            }
            result
        })
    }
    
    fn main() {
      let sum_of_first_n = firstn(1000000).sum::();
      println!("sum(0 to 999999): {}", sum_of_first_n);
    }
    

    std::iter::successors is also available. It is less general but might be a bit easier to use since you just pass around the seed value explicitly. (i.e. it takes an initial value T and a successor function FnMut(&T) -> Option to create an Iterator)

    fn firstn(n: u64) -> impl std::iter::Iterator {
        std::iter::successors(
            Some(0),
            move |&num| {
                if num + 1 < n {
                    Some(num + 1)
                } else {
                    None
                }
            },
        )
    }
    

    However, Shepmaster's note applies to these utility too. (tldr: often, hand-rolled Iterator is more memory efficient)

    What's interesting about this is that it's less powerful than an implementation of Iterator. For example, iterators have the size_hint method, which allows consumers of the iterator to have an idea of how many elements are remaining. This allows optimizations when collecting into a container. Generators do not have any such information.

    (Note: returning impl is a Rust 2018 feature. See the Edition Guide for details)

提交回复
热议问题