如何将Vec转换为数组而不复制元素?

时间:2018-03-16 19:40:40

标签: arrays vector rust

我有一个Vec非平凡的类型,我确定它的大小。我需要将其转换为固定大小的数组。理想情况下我想这样做

  1. 没有复制数据 - 我想使用Vec
  2. 没有使用零数据预初始化数组,因为这会浪费CPU周期
  3. 问题写成代码:

    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复制所有元素,但这不符合我的要求。

3 个答案:

答案 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给予您对其元素的所有权的基本方法是removepopdraininto_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。