2014-11-05 78 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確實有一個警告:

注:此功能可能產生不成比例的大開銷陣列搬出來,它的性能是不是最佳的。

正因爲如此,您只想將數據保留在原來的位置。你仍然避免了堆分配。