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

boo*_*gie 13 arrays iteration rust

刚开始使用 Rust,我正在尝试一些数组的东西,但遇到了一些困难。第一个问题是初始化。我可以创建一个“空”数组并迭代元素来填充它,但如何从范围初始化?:

let mut arr: [i32; 5] = [0; 5]; // this works
// let mut arr: [i32; 5] = 1..5 //this doesn't
Run Code Online (Sandbox Code Playgroud)

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

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

事实上,即使打印(不分配)也不起作用:

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`"
Run Code Online (Sandbox Code Playgroud)

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

aed*_*edm 25

从 Rust 1.63 开始

使用from_fn

let array: [usize; 5] = core::array::from_fn(|i| i + 1);
assert_eq!(array, [1, 2, 3, 4, 5]);
Run Code Online (Sandbox Code Playgroud)

  • @anilbey 因为这里的参数“i”指的是索引而不是值 (4认同)

Kev*_*eid 14

这里的一般问题是数组具有固定大小,在编译时已知,但迭代器中的项数在编译时未知 \xe2\x80\x94 即使它是一个ExactSizeIterator,也有没有大小常量参数。因此,不存在从迭代器到数组的绝对正确的转换。

\n

然而,也存在一些容易出错的转换。最直接常用的是impl<T, A, const N: usize> TryFrom<Vec<T, A>> for [T; N],它允许您将 a 转换Vec<T>[T; N],如果向量长度错误则失败。

\n
use std::convert::TryInto;\n\nlet arr: [i32; 5] = (1..=5).collect::<Vec<_>>()\n    .try_into().expect("wrong size iterator");\n
Run Code Online (Sandbox Code Playgroud)\n

这样做的缺点是需要为 进行临时堆分配Vec并丢弃它。如果您确实希望数组位于堆上,那么您可能需要使用TryFrom<Box<[T], Global>> for Box<[T; N], Global>它,它允许您从装箱切片中获取装箱数组。

\n
let arr: Box<[i32; 5]> = (1..=5)\n    .collect::<Box<[i32]>>()\n    .try_into().expect("wrong size iterator");\n
Run Code Online (Sandbox Code Playgroud)\n

如果您希望数组被堆栈分配并避免临时分配,那么您将不得不使用std::iter::from_fn(),有点尴尬:

\n
let mut iter = 1..=5;\nlet arr: [i32; 5] = std::array::from_fn(|_| iter.next().expect("too short"));\nassert!(iter.next().is_none(), "too long");\n
Run Code Online (Sandbox Code Playgroud)\n

(如果您对长度有信心,则无需事后断言,但内部的期望/展开是不可避免的。)

\n
\n
\n

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

\n
let mut arr2: [i32; 5] =  arr.iter().map(|&x| x + 1).collect();\n
Run Code Online (Sandbox Code Playgroud)\n
\n

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

\n

由于这个问题和答案最初是写的,数组现在获得了一种方法map,您可以使用它来执行此操作,而无需通过迭代器:

\n
let mut arr2: [i32; 5] = arr.map(|x| x + 1);\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n

事实上,即使打印(不分配)也不起作用:

\n
\n

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

\n

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

\n
println!("{:?}", arr.iter().map(|&x| x + 1).collect::<Vec<_>>());\n
Run Code Online (Sandbox Code Playgroud)\n