我怎样才能像在node.js Readable.compose中那样每次都编写没有样板的迭代器适配器

问题描述 投票:0回答:1

我希望能够编写甚至支持

genawaiter
板条箱的迭代器,并避免每个迭代器适配器的样板文件

我希望能够做到这一点(我知道我可以使用映射运算符,但这是当我需要在迭代器中拥有某些状态时的简化示例):

use genawaiter::{rc::gen, yield_};
use std::iter::Iterator;

fn wrap_with_option<Input, I: Iterator<Item = Input>>(iter: I) -> impl Iterator<Item = Option<Input>> {
    return gen!({
            for item in iter {
                yield_!(Some(item));
            }
        })
    .into_iter();
}
fn run() {

    let input: Vec<i32> = vec![1, 2, 3, 4, 5];
    let output: Vec<Option<&i32>> = input
        .iter()
        .compose(wrap_with_option)
        .collect();

    let expected = vec![
        Some(&1),
        Some(&2),
        Some(&3),
        Some(&4),
        Some(&5)
    ];
    assert_eq!(output, expected);
}
rust iterator
1个回答
0
投票

你可以这样做:

它将与任何获取迭代器并返回迭代器的函数一起使用,

它只是在全局迭代器上实现 compose 函数,获取一个函数并在当前迭代器(自身)上执行它并返回函数结果 - 新迭代器

use std::iter::Iterator;

pub trait ComposeByIterator: Iterator {
    fn compose<F, OutputItem, OutputIterator>(self,f: F) -> OutputIterator
    where
        Self: Sized,
        OutputIterator: Iterator<Item = OutputItem>,
        F: Fn(Self) -> OutputIterator,
    {
        f(self)
    }
}
impl<I: Iterator> ComposeByIterator for I {}

#[cfg(test)]
mod tests {
    use genawaiter::{rc::gen, yield_};

    use super::*;

    #[test]
    fn should_allow_changing_the_input_type() {
        let input = vec![1, 2, 3, 4, 5];
        let output: Vec<String> = input
            .iter()
            .compose(|iter| iter.map(|x| x.to_string()))
            .collect();

        let expected = vec![
            "1".to_string(),
            "2".to_string(),
            "3".to_string(),
            "4".to_string(),
            "5".to_string(),
        ];
        assert_eq!(output, expected);
    }

    #[test]
    fn should_allow_multiple_compositions() {
        let input = vec![1, 2, 3, 4, 5];
        let output: Vec<String> = input
            .iter()
            .compose(|iter| iter.map(|x| x.to_string()))
            .compose(|iter| iter.map(|x| x + "!"))
            .collect();

        let expected = vec![
            "1!".to_string(),
            "2!".to_string(),
            "3!".to_string(),
            "4!".to_string(),
            "5!".to_string(),
        ];
        assert_eq!(output, expected);
    }

    #[test]
    fn should_allow_multiple_compositions_that_change_type() {
        #[derive(Debug, PartialEq)]
        struct MyStruct {
            value: String,
        }
        let input = vec![1, 2, 3, 4, 5];
        let output: Vec<MyStruct> = input
            .iter()
            .compose(|iter| iter.map(|x| x.to_string()))
            .compose(|iter| iter.map(|x| MyStruct { value: x }))
            .collect();

        let expected = vec![
            MyStruct {
                value: "1".to_string(),
            },
            MyStruct {
                value: "2".to_string(),
            },
            MyStruct {
                value: "3".to_string(),
            },
            MyStruct {
                value: "4".to_string(),
            },
            MyStruct {
                value: "5".to_string(),
            },
        ];
        assert_eq!(output, expected);
    }

    #[test]
    fn should_support_gen() {
        fn wrap_with_option<Input, I: Iterator<Item = Input>>(iter: I) -> impl Iterator<Item = Option<Input>> {
            return gen!({
                for item in iter {
                    yield_!(Some(item));
                }
            })
            .into_iter();
        }

        let input: Vec<i32> = vec![1, 2, 3, 4, 5];
        let output: Vec<Option<&i32>> = input
            .iter()
            .compose(wrap_with_option)
            .collect();

        let expected = vec![
            Some(&1),
            Some(&2),
            Some(&3),
            Some(&4),
            Some(&5)
        ];
        assert_eq!(output, expected);
        
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.