繁体   English   中英

`选项数组<t> ` 到 `Option` 数组</t>

[英]Array of `Option<T>` to `Option` array

我正在尝试使用固定大小的 arrays。我想转换一个Option值数组[Option<T>; N] [Option<T>; N]Option<[T; N]> Option<[T; N]>如果所有条目都是Some ,我得到Some ,否则我得到None

Rust 通常使用迭代器来转换 collections,但这些没有长度保证。

这应该是合法的,因为如果存在,结果必须与参数的长度相同,但是有没有办法在不使用unwrap或类似的情况下保留编译时长度保证的情况下做到这一点?

每晚,使用try_map() (也许有一个稳定的板条箱支持它,我不知道):

#![feature(array_try_map)]

pub fn convert<T, const N: usize>(arr: [Option<T>; N]) -> Option<[T; N]> {
    arr.try_map(|v| v)
}

在稳定的情况下,分配:

pub fn convert<T, const N: usize>(arr: [Option<T>; N]) -> Option<[T; N]> {
    let arr = arr.into_iter().collect::<Option<Vec<T>>>()?;
    Some(
        arr.try_into()
            .unwrap_or_else(|_| panic!("the array is of size {N}")),
    )
}

在稳定的、非分配的情况下,但需要Default并且可能效率低下:

pub fn convert<T: Default, const N: usize>(arr: [Option<T>; N]) -> Option<[T; N]> {
    let mut result = [(); N].map(|()| T::default());
    for (item, result_item) in std::iter::zip(arr, &mut result) {
        *result_item = item?;
    }
    Some(result)
}

在稳定的,非分配的,使用不安全的。 应该是最后的手段。 下面的代码有点不正确,因为它不会在中间None的情况下丢弃元素,这只是说明编写正确的不安全代码有多么困难:

use std::mem::{ManuallyDrop, MaybeUninit};

pub fn convert<T, const N: usize>(arr: [Option<T>; N]) -> Option<[T; N]> {
    let arr = ManuallyDrop::new(arr);
    let mut result_arr = MaybeUninit::<[T; N]>::uninit();
    for (i, item) in arr.iter().enumerate() {
        // SAFETY: This is in bounds, and wrapped in `ManuallyDrop` so not double drop.
        unsafe {
            result_arr
                .as_mut_ptr()
                .cast::<T>()
                .add(i)
                .write(std::ptr::read(item)?);
        }
    }
    // SAFETY: We initialized it above.
    Some(unsafe { result_arr.assume_init() })
}

您可以将.collect()放入Option<Vec<T>>.and_then(|v| v.try_into().ok())

fn convert<T, const N: usize>(a: [Option<T>; N]) -> Option<[T; N]> {
    a.into_iter().collect::<Option<Vec<_>>>().and_then(|a| a.try_into().ok())
}

这是直接和安全的,但不幸的是创建了一个中间Vec因为TOption<T>有不同的大小我认为你不能做得更好。 由于数组 ( [T;N] ) 上的迭代器总是产生Na.try_into().ok()将总是导致Some

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM