Rust 数组从范围或收集初始化

rust array initialization from range or collect

刚开始使用 rust,我正在尝试使用数组和 运行 遇到一些困难。第一个问题是初始化。我可以创建一个“空”数组并遍历元素来填充它,但是我如何从一个范围进行初始化?:

let mut arr: [i32; 5] = [0; 5]; // this works
// let mut arr: [i32; 5] = 1..5 //this doesn't

第二个问题是尝试从 i32 上的数组上的简单映射初始化数组。这不起作用:

let mut arr2: [i32; 5] =  arr.iter().map(|&x| x + 1).collect();

确实连打印(不赋值)都行不通:

println!("{:?}", arr.iter().map(|&x| x + 1).collect());
// the above fails with: "type annotations needed: cannot infer type for type arameter `B` declared on the associated function `collect`"

有什么智慧的话可以提供吗?

这里的一般问题是数组具有固定大小,在编译时已知,但迭代器中的项数在编译时未知——即使它是 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");

如果您希望对数组进行堆栈分配并避免临时分配,那么您(目前)只能使用显式循环,据我所知:

let mut arr: [i32; 5] = [0; 5];
for (elem, val) in arr.iter_mut().zip(1..=5) {
    *elem = val;
}

如果迭代器的项数错误,这个版本不会失败;它会丢弃多余的项目,如果项目太少,则将数组保留为零。您可以添加自己的错误检查,或者使用 Itertools::zip_eq 而不是内置的 Iterator::zip 在长度错误时恐慌。


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

由于与第一个相同的原因,这不起作用:您当前不能直接收集到数组中。我上面提到的任何技术也适用于这种情况。

在 nightly/unstable Rust 中,数组也有一个方法 map,您可以使用它来执行此操作而无需通过迭代器:

#![feature(array_map)]

let mut arr2: [i32; 5] = arr.map(|x| x + 1);

Indeed even printing (without assigning) doesn't work:

这实际上是一个与其他问题不同的问题。 println!("{:?}", some_iterator.collect()) 总是会失败,因为 你还没有指定收集到什么类型。 collect() 从不假设一个收集类型;它总是必须从上下文中指定或推断。

如果指定类型,则可以打印迭代器的结果;原始输入是否为数组无关紧要。

println!("{:?}", arr.iter().map(|&x| x + 1).collect::<Vec<_>>());