首页 > 解决方案 > 限制为 const N 时的 mem::transmute 错误

问题描述

我不明白为什么编译器不让这个例子编译:


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


fn foo<const N: usize>() -> [u32; N] {
    let mut res: [MaybeUninit<u32>; N] = unsafe { MaybeUninit::uninit().assume_init() };

    for elem in &mut res[..] {
        unsafe { elem.as_mut_ptr().write(0) };
    }

    unsafe { mem::transmute::<[MaybeUninit<u32>; N], [u32; N]>(res) }
}
Compiling playground v0.0.1 (/playground)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
  --> src/lib.rs:11:14
   |
11 |     unsafe { mem::transmute::<[MaybeUninit<u32>; N], [u32; N]>(res) }
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: source type: `[MaybeUninit<u32>; N]` (this type does not have a fixed size)
   = note: target type: `[u32; N]` (this type does not have a fixed size)

error: aborting due to previous error

很明显,N 对于结果和输入数组都是相同的。有没有办法做到这一点?

操场

标签: rust

解决方案


这是编译器的限制。它们的大小确实相同,但编译器无法看到(还没有?)。

您可以使用原始指针转换来实现这一点,因为编译器不会检查大小是否相等:

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

fn foo<const N: usize>() -> [u32; N] {
    let mut res: [MaybeUninit<u32>; N] = unsafe { MaybeUninit::uninit().assume_init() };

    for elem in &mut res[..] {
        unsafe { elem.as_mut_ptr().write(0) };
    }

    unsafe { *(&res as *const [MaybeUninit<u32>; N] as *const [u32;N] ) }
}

或者有array_assume_init,但仍然不稳定,所以只在夜间使用。

#![feature(maybe_uninit_array_assume_init)]

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

fn foo<const N: usize>() -> [u32; N] {
    let mut res: [MaybeUninit<u32>; N] = unsafe { MaybeUninit::uninit().assume_init() };

    for elem in &mut res[..] {
        unsafe { elem.as_mut_ptr().write(0) };
    }

    unsafe { MaybeUninit::array_assume_init(res) }
}

推荐阅读