问题在于数组具有固定大小,编译时已知,但迭代器中的项数在编译时不可知即使它是一个 ExactSizeIterator,也没有 const 参数表示大小。因此,无法从迭代器到数组进行无误转换。
然而,有可失败的转换可用。最直接、常用的一种是
impl<T, A, const N: usize> TryFrom<Vec<T, A>> for [T; N]
,它允许你将
Vec<T>
转换为
[T; N]
,如果向量长度不正确则转换失败。
use std::convert::TryInto;
let arr: [i32; 5] = (1..=5).collect::<Vec<_>>()
.try_into().expect("wrong size iterator");
这种方法的缺点是会为Vec
进行临时堆分配并将其丢弃。如果您确实希望数组存储在堆上,则可能需要使用TryFrom<Box<[T], Global>> for Box<[T; N], Global>
,它允许您从一个盒装切片中获取一个盒装数组。
let arr: Box<[i32; 5]> = (1..=5)
.collect::<Box<[i32]>>()
.try_into().expect("wrong size iterator");
如果您希望将数组分配给栈并避免临时分配,则必须使用std::iter::from_fn()
进行操作,稍微有些麻烦:
let mut iter = 1..=5;
let arr: [i32; 5] = std::array::from_fn(|_| iter.next().expect("too short"));
assert!(iter.next().is_none(), "too long");
(如果您对长度有信心,那么之后就没有必要再进行断言,但内部的 expect/unwrap 是不可避免的。)
The second problem is trying to initialize an array from a simple map over an array on i32. This doesn't work:
let mut arr2: [i32; 5] = arr.iter().map(|&x| x + 1).collect();
由于同样的原因,第一个方法也行不通:你目前不能直接收集到数组中。我上面提到的任何技巧都适用于这种情况。
自从这个问题和答案最初写出来以来,数组现在已经拥有了一个
map
方法,您可以使用它来完成此操作,而无需通过迭代器进行操作:
let mut arr2: [i32; 5] = arr.map(|x| x + 1);
实际上,这是一个不同于其他问题的问题。即使没有赋值,打印(printing)也不起作用:
println!("{:?}", some_iterator.collect())
总是会失败,因为你没有指定要收集到哪种类型中。collect() 从不假设收集类型,它总是需要在上下文中被指定或者推断出来。如果你指定了一个类型,那么你就可以打印迭代器的结果;原始输入是否为数组都是无关紧要的。
println!("{:?}", arr.iter().map(|&x| x + 1).collect::<Vec<_>>());