Rust中枚举的平坦向量

  • 本文关键字:向量 枚举 Rust rust
  • 更新时间 :
  • 英文 :


我正试图在Rust中压平Enum的向量,但我遇到了一些问题:

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循环并将元素插入到现有的向量中,但这并不有趣。我想知道是否有更惯用的Rust方法。

这里有一种方法可以产生迭代器(而不一定是向量,就像基于fold()的解决方案那样(。

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中,这并不能满足您的要求,而且您实际上无法返回迭代器,原因有点尴尬(这将在即将推出的Rust版本中修复(。然后,如果确实是你想要的,那么你会得到一个错误,因为两个match臂的类型不相等——一个是[i32; 1]上的迭代器,另一个是[i32; 2]上的迭代器。

    相反,您需要构建两个可能的迭代器,它们显然是相同的类型。有很多方法可以做到这一点,我选择的方法是使用Iterator::chain将返回单个元素i的迭代器once(i)与包含第二个元素j(如果存在(的Option<i32>(实现IntoIterator(组合起来。

    注意,在第一个match臂中,我写下了看似无用的表达式.chain(None);这使得两个臂具有相同的类型。写同样东西的另一种方法是:,这可以说更清楚,因为它不会复制必须相同的代码

    let (i, opt_j) = match f {
    &Foo::A(i) => (i, None),
    &Foo::B(i, j) => (i, Some(j)),
    };
    once(i).chain(opt_j)
    

    在任何一种情况下,迭代器的类型都是std::iter::Chain<std::iter::Once<i32>, std::option::IntoIter<i32>>——您不需要确切地知道这一点,只需注意必须有一个处理A(i)B(i, j)情况的类型。

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

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
});
}

最新更新