我有一个Vec
非平凡的类型,我确定它的大小。我需要将其转换为固定大小的数组。理想情况下我想这样做
Vec
问题写成代码:
struct Point {
x: i32,
y: i32,
}
fn main() {
let points = vec![
Point { x: 1, y: 2 },
Point { x: 3, y: 4 },
Point { x: 5, y: 6 },
];
// I would like this to be an array of points
let array: [Point; 3] = ???;
}
这似乎是一个微不足道的问题,但是我无法在Vec
文档中找到令人满意的解决方案,切片Rust Books或Googling。我发现的只是先用零数据初始化数组,然后从Vec
复制所有元素,但这不符合我的要求。
答案 0 :(得分:3)
正确地执行此操作非常困难。问题在于当存在部分未初始化的阵列时正确处理恐慌。如果数组中的类型实现Drop
,那么它将访问未初始化的内存,从而导致未定义的行为。
最简单,最安全的方法是使用arrayvec:
extern crate arrayvec;
use arrayvec::ArrayVec;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let points = vec![
Point { x: 1, y: 2 },
Point { x: 3, y: 4 },
Point { x: 5, y: 6 },
];
let array: ArrayVec<_> = points.into_iter().collect();
let array: [Point; 3] = array.into_inner().unwrap();
println!("{:?}", array);
}
请注意,这仅适用于specific sizes of arrays,因为Rust还没有通用整数。 into_inner
也有一个你应该注意的表现警告。
另见:
答案 1 :(得分:1)
只是为了好玩,以下示例显示安全Rust为我们提供了针对特定小尺寸的方法,例如:
/// Return the array inside Some(_), or None if there were too few elements
pub fn take_array3<T>(v: &mut Vec<T>) -> Option<[T; 3]> {
let mut iter = v.drain(..);
if let (Some(x), Some(y), Some(z))
= (iter.next(), iter.next(), iter.next())
{
return Some([x, y, z]);
}
None
}
/// Convert a Vec of length 3 to an array.
///
/// Panics if the Vec is not of the exact required length
pub fn into_array3<T>(mut v: Vec<T>) -> [T; 3] {
assert_eq!(v.len(), 3);
let z = v.remove(2);
let y = v.remove(1);
let x = v.remove(0);
[x, y, z]
}
让Vec
给予您对其元素的所有权的基本方法是remove
,pop
,drain
,into_iter
等。
答案 2 :(得分:0)
还有try_into
吗?
use std::convert::TryInto;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let v: Vec<Point> = vec![Point { x: 1, y: 1 }, Point { x: 2, y: 2 }];
let a: &[Point; 2] = v[..].try_into().unwrap();
println!("{:?}", a);
}
它是一成不变地借来的,所以不会消耗Vec。