rust 如何使用函数初始化数组?

vmjh9lq9  于 2022-11-12  发布在  其他
关注(0)|答案(5)|浏览(215)

我想在Rust中创建一个包含10个空向量的数组,但是[Vec::new(); 10]不起作用,因为Vec没有实现Copy。我该怎么做呢?更一般地说,我该怎么通过重复调用函数来初始化数组呢?

mqkwyuun

mqkwyuun1#

您可以使用数组的.map()方法来执行一般函数:

let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));

(As Rust 1.55.0,2021年9月。Rust 1.63.0,2022年8月,考虑使用from_fn

6pp0gazn

6pp0gazn2#

对于您的特定情况,可以只使用Default

let v: [Vec<String>; 10] = Default::default();

对于一般情况,可以从函数中创建一个迭代器,然后使用ArrayVec将其收集到数组中:

use arrayvec::ArrayVec; // 0.4.10
use std::iter;

fn make<R>(f: impl FnMut() -> R) -> [R; 10] {
    let a: ArrayVec<_> = iter::repeat_with(f).collect();
    a.into_inner()
        .unwrap_or_else(|_| panic!("Did not have enough elements"))
}

fn main() {
    let mut a = 0;
    let arr = make(|| {
        a += 3;
        a
    });

    println!("{:?}", arr);
    // [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
}

另请参阅:

dpiehjr4

dpiehjr43#

我看到两种可能的方法

第一个

使用宏的简单解决方案

macro_rules! array {
    ($v: expr; 1) => ([$v]);
    ($v: expr; 2) => ([$v, $v]);
    ($v: expr; 3) => ([$v, $v, $v]);
    ($v: expr; 4) => ([$v, $v, $v, $v]);
    ($v: expr; 5) => ([$v, $v, $v, $v, $v]);
    // until 32
}

let a = array![Vec::new(); 3];

这有点冗长,但即使是标准库也使用这种结构。

第二个

在认识到这个问题与another that I had answered before之间的联系之后,我使用nodrop编写了这个解决方案

extern crate nodrop;

macro_rules! array {
    ($e: expr; $n:expr) => (
        {
            use std::mem;
            use std::ptr;
            use nodrop::NoDrop;

            struct ArrayBuilder<T> {
                len: usize,
                data: *mut T,
            }

            impl<T> Drop for ArrayBuilder<T> {
                fn drop(&mut self) {
                    unsafe {
                        while self.len > 0 {
                            let offset = (self.len as isize) - 1;
                            self.len -= 1;
                            ptr::drop_in_place(self.data.offset(offset));
                        }
                    }
                }
            }

            let mut v: NoDrop<[_; $n]> = NoDrop::new(unsafe {
                mem::uninitialized()
            });
            // helps type inference for v
            if false { v[0] = $e; }
            let mut builder = ArrayBuilder {
                len: 0,
                data: (&mut *v as *mut _) as *mut _
            };
            unsafe {
                for i in 0..$n {
                    ptr::write(builder.data.offset(i as isize), $e);
                    builder.len = i + 1;
                }
            }
            builder.len = 0;
            v.into_inner()
        }
    )
}

let a = array![Vec::new(); 3];

以及 * 指示 * 它不会泄漏内存的测试


# [test]

fn test() {
    static mut COUNT: usize = 0;

    #[derive(Debug)]
    struct X(usize);

    impl Drop for X {
        fn drop(&mut self) {
            println!("drop {:?}", self.0);
        }
    }

    impl X {
        fn new() -> X {
            unsafe {
                if COUNT == 3 {
                    panic!();
                }
                let x = X(COUNT);
                COUNT += 1;
                x
            }
        }
    }

    array![X::new(); 6];
}

在此测试中,方法X::new在建立X(3)时会死机,因此必须卸除X(0)X(1)X(2)

其他

有一个不安全的解决方案here

unguejic

unguejic4#

自生 rust 1.63起

使用from_fn

let array: [usize; 5] = core::array::from_fn(|i| i * 2);
assert_eq!(array, [0, 2, 4, 8, 10]);
rkue9o1l

rkue9o1l5#

有一个名为arr_macro的板条箱,它可以完全满足您的需求:

fn main() {
    let array: [Vec<String>; 10] = arr![Vec::new(); 10];
    println!("{:?}", array) // [[], [], [], [], [], [], [], [], [], []]
}

相关问题