首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >锈菌的扁平矢量

锈菌的扁平矢量
EN

Stack Overflow用户
提问于 2021-05-01 12:30:45
回答 2查看 1.1K关注 0票数 2

我试图将锈蚀中的Enum矢量扁平化,但我遇到了一些问题:

代码语言:javascript
复制
enum Foo {
    A(i32),
    B(i32, i32),
}

fn main() {
    let vf = vec![Foo::A(1), Foo::A(2), Foo::B(3, 4)];

    let vi: Vec<i32> = vf
        .iter()
        .map(|f| match f {
            Foo::A(i) => [i].into_iter(),
            Foo::B(i, j) => [i, j].into_iter(),
        })
        .collect(); // this does not compile

    // I want vi = [1, 2, 3, 4]. vf must still be valid
}

我可以使用正则for循环并将元素插入到现有的向量中,但这并不有趣。我想知道是否有一种更地道的生锈方式。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-05-01 15:45:20

下面是一种生成迭代器的方法(而不是像基于fold()的解决方案那样,必然是一个向量)。

代码语言:javascript
复制
use std::iter::once;

enum Foo {
    A(i32),
    B(i32, i32),
}

fn main() {
    let vf = vec![Foo::A(1), Foo::A(2), Foo::B(3, 4)];

    let vi: Vec<i32> = vf
        .iter()
        .flat_map(|f| {
            match f {
                &Foo::A(i) => once(i).chain(None),
                &Foo::B(i, j) => once(i).chain(Some(j)),
            }
        })
        .collect();

    dbg!(vi);
}

这基本上和你所尝试的一样,但在某种程度上是成功的。下面是我更改的部分,按照它们在代码中的出现顺序:

  1. 我用的是.flat_map()而不是.map()flat_map接受一个函数,该函数返回迭代器并生成该迭代器的元素(“平坦”),而.map()只需要给出迭代器。
  2. 我在&模式中使用了match。这是因为,由于您在向量上使用.iter() (这适合您的需求“vf必须仍然有效”),所以您有对枚举的引用,并且对枚举的引用通常会给出对其元素的引用,但是我们几乎肯定希望通过值来处理i32。我还可以做一些其他的事情,比如在值上使用*取消引用操作符,但是这是简洁和整洁的。
  3. 您试图.into_iter()一个数组。不幸的是,在当前的Rust中,由于一些尴尬的原因(将在即将发布的锈菌版本中修复),这并不能满足您的需要,而且您实际上无法返回那个迭代器。然后,如果它确实是您想要的,那么您就会得到一个错误,因为两个match臂有不同的类型--一个是[i32; 1]上的迭代器,另一个是[i32; 2]上的迭代器。 相反,您需要构建两个可能的迭代器,它们显然是相同类型的。有很多方法可以做到这一点,我选择的方法是使用Iterator::chain将返回单个元素i的迭代器once(i)与包含第二个元素j (如果存在的话包含第二个元素j)的Option<i32> (实现IntoIterator)结合起来。 注意,在第一个match arm中,我编写了一个看似无用的表达式.chain(None);这使得这两个臂具有相同的类型。另一种编写相同东西的方法,可以说更清楚,因为它不重复必须相同的代码,是: 设(i,opt_j) =匹配f{ &Foo::A(i) => (i,None),&Foo:B (i,j) => (I,Some(j)),};一次(I).chain(Opt_j) 在这两种情况下,迭代器的类型都是std::iter::Chain<std::iter::Once<i32>, std::option::IntoIter<i32>> --您不需要确切地知道这一点,只需注意,必须有一种同时处理A(i)B(i, j)情况的类型。
票数 4
EN

Stack Overflow用户

发布于 2021-05-01 13:35:20

首先,您需要将i32引用更改为拥有的值,例如取消引用。然后,您可以通过使用fold()绕过内联数组的代理。

代码语言:javascript
复制
enum Foo {
    A(i32),
    B(i32, i32),
}

fn main() {
    let vf = vec![Foo::A(1), Foo::A(2), Foo::B(3, 4)];

    let vi: Vec<i32> = vf
        .iter()
        .fold(Vec::new(), |mut acc, f| {
            match f {
                Foo::A(i) => acc.push(*i),
                Foo::B(i, j) => {
                    acc.push(*i);
                    acc.push(*j);
                }
            }
            acc
        });

}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67346301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档