代码之家  ›  专栏  ›  技术社区  ›  Boiethios

如何在堆栈上创建按值迭代器

  •  3
  • Boiethios  · 技术社区  · 6 年前

    vec![1, 10, 100].into_iter()
    

    我还可以在堆栈上创建一个迭代器来借用元素:

    [1, 10, 100].iter()
    

    [1, 10, 100].into_iter()
    

    这不是一个消耗迭代器,因为 [T; _]::into_iter IntoIterator 仅对借用的版本(即切片)实现。最简单的方法是 std lib)在堆栈上创建一个消费迭代器?


    我知道 [1, 10, 100].iter().cloned() 可以,但这要求项是可克隆的。

    2 回复  |  直到 5 年前
        1
  •  2
  •   E_net4 Tunn    5 年前

    可以有一个宏,它将值包装在 once 迭代器和 chains 他们一起:

    macro_rules! value_iter {
        () => {
            std::iter::empty()
        };
        ($v: expr, $( $rest: expr ), +) => {
            std::iter::once($v).chain(
                value_iter!($($rest),*)
            )
        };
        ($v: expr) => {
            std::iter::once($v)
        };
    }
    

    使用:

    #[derive(Debug, PartialEq)]
    struct Foo;
    
    let it = value_iter![Foo, Foo, Foo];
    
    let all: Vec<_> = it.collect();
    assert_eq!(all, vec![Foo, Foo, Foo]);
    

    一个已知的缺点是迭代器不是一个精确大小的迭代器,因此编译器可能会错过一些明显的优化。

    Playground

        2
  •  6
  •   mcarton    6 年前

    最简单的方法是 std

    不。

    简单的 方式 (最好在标准库中) 在堆栈上创建一个消费迭代器?

    对。用板条箱 stack smallvec ,它提供实现 IntoIterator .

        3
  •  3
  •   Boiethios    5 年前

    非常难看,但从技术上讲是可行的:

    for s in [
        Some(String::from("hello")),
        Some(String::from("goodbye"))
    ].iter_mut().map(|option| option.take().unwrap()) {
        let s: String = s;
        println!("{}", s);
    }
    

    macro_rules! iter {
        [ $( $item:expr ),+ ] => {{
            [ $( Some($item), )+ ]
            .iter_mut()
            .map(|o| o.take().unwrap())
        }};
        // Rule to allow a trailing comma:
        [ $( $item:expr, )+ ] => {{
            iter![ $( $item ),+ ]
        }};
    }
    
    fn main() {
        for s in iter![String::from("hello"), String::from("goodbye")] {
            println!("{}", s);
        }
    }