2014-11-05 41 views
10

我想打电话给.map()枚举阵列上:如何收集数组?

enum Foo { 
    Value(i32), 
    Nothing, 
} 

fn main() { 
    let bar = [1, 2, 3]; 
    let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>(); 
} 

但是编译器会抱怨:

error[E0277]: the trait bound `[Foo; 3]: std::iter::FromIterator<Foo>` is not satisfied 
--> src/main.rs:8:51 
    | 
8 |  let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>(); 
    |             ^^^^^^^ a collection of type `[Foo; 3]` cannot be built from an iterator over elements of type `Foo` 
    | 
    = help: the trait `std::iter::FromIterator<Foo>` is not implemented for `[Foo; 3]` 

我该怎么办呢?

回答

4

这是不可能的,因为数组没有实现任何特征。您只能收集实现FromIterator特质的类型(请参阅its docs底部的列表)。

这是一种语言限制,因为目前不可能在数组长度上是通用的,并且长度是其类型的一部分。但是,即使可能是,也不太可能在阵列上实现FromIterator,因为如果产生的项数不完全是阵列的长度,它将不得不恐慌。

+2

数组确实实现了特征,至少是短特征。标准库包含很多用于短阵列的实现(我认为最多有12个元素)。问题是你不能为所有数组做一个通用的实现,并且没有数组实现FromIterator。 – 2016-11-06 23:19:59

6

在这种情况下,你可以使用Vec<Foo>

#[derive(Debug)] 
enum Foo { 
    Value(i32), 
    Nothing, 
} 

fn main() { 
    let bar = [1, 2, 3]; 
    let foos = bar.iter().map(|&x| Foo::Value(x)).collect::<Vec<Foo>>(); 
    println!("{:?}", foos); 
} 
15

的问题实际上是collect,而不是在map

为了能够将迭代的结果收集到容器中,此容器应该实现FromIterator。使用FromIterator当你作出任何有关将被送入你的类型元素的数量保证生产需要准确提供n元素[T; n],但是:

[T; n]没有实现FromIterator,因为它不能这样做一般。

如果没有补充数据,您还不知道现在应该输入哪个数组的哪个索引(以及它是空的还是满的)等等......这可以通过在enumerate之后使用enumerate来解决map(主要是提供索引),但是如果没有足够的元素或者提供的元素太多,您仍然会遇到决定该做什么的问题。

因此,不仅目前不能在固定大小的数组上实现FromIterator;但即使在未来,它似乎也是一个长镜头。


那么,现在该怎么办?有几种可能性:

  • 直列转型在调用点:[Value(1), Value(2), Value(3)],可能与中宏
  • 的帮助下收集到不同的(可扩展的)容器中,如Vec<Foo>
  • ...
0

我自己遇到了这个问题 - 这是一个解决方法。

您不能使用FromIterator,但是您可以遍历固定大小对象的内容,或者如果情况更复杂,则可以对可以访问的任何内容进行切片。无论哪种方式,突变是可行的。

例如,我有问题是与[[usize; 2]; 4]类型的数组:

fn main() { 
    // Some input that could come from another function and thus not be mutable 
    let pairs: [[usize; 2]; 4] = [[0, 0], [0, 1], [1, 1], [1, 0]]; 

    // Copy mutable 
    let mut foo_pairs = pairs.clone(); 

    for pair in foo_pairs.iter_mut() { 
     // Do some operation or other on the fixed-size contents of each 
     pair[0] += 1; 
     pair[1] -= 1; 
    } 
    // Go forth and foo the foo_pairs 
} 

如果这是一个小功能内部发生,这是在我的书好。无论哪种方式,您最终都会得到与同一类型相同类型的变换值,因此首先复制整个事物然后进行变异与在闭包中引用一个值并返回其某个函数的工作量大致相当。

请注意,这仅适用于计划计算将会是相同类型的东西,直到并包括大小/长度的情况。但是这是你使用Rust数组的暗示。 (具体而言,你可以为你喜欢Value()Foo S或Nothing他们,仍然是类型参数为您的阵列中)

-2

Vec<T>转化为[T],你可以写:

vec.as_ref(); 

注结果不是大小的,并且期望[T]的函数也可以接受Vec<T>

+0

这不会像OP请求那样创建* array *; [它创建* slice *('&[T]')](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-AsRef <[T]>) – Shepmaster 2017-11-08 18:16:15

0

虽然你不能直接收集到一个数组由其他的答案中阐明的原因,这并不意味着你不能收集到由数组支持的数据结构,就像一个ArrayVec

extern crate arrayvec; 

use arrayvec::ArrayVec; 

enum Foo { 
    Value(i32), 
    Nothing, 
} 

fn main() { 
    let bar = [1, 2, 3]; 
    let foos: ArrayVec<[_; 3]> = bar.iter().map(|x| Foo::Value(*x)).collect(); 
    let the_array = foos.into_inner() 
     .unwrap_or_else(|_| panic!("Array was not completely filled")); 
} 

将数组拉出ArrayVec将返回一个Result来处理没有足够的项目来填充它的情况;其他答案中讨论过的情况。

into_inner确实有一个警告:

注:此功能可能产生不成比例的大开销阵列搬出来,它的性能是不是最佳的。

正因为如此,您只想将数据保留在原来的位置。你仍然避免了堆分配。