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<_>>());
刚开始使用 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<_>>());