我正在try 创建一个包含常量数组的容器对象, for each 元素使用一个常量初始值设定项函数.
对于固定大小的数组(用整数表示),它是already solved;这里的问题是数组的长度是常量泛型.
另一个转折是,我需要no_std
(核心)模式下的整个东西.
下面是一个代码示例,它演示了我的问题:
// Important: Element is **not** `Copy`.
#[derive(Debug)]
struct Element(usize);
impl Element {
pub const fn array_initializer(pos: usize) -> Self {
Element(pos)
}
}
#[derive(Debug)]
pub struct Container<const N: usize> {
data: [Element; N],
}
impl<const N: usize> Container<N> {
pub const fn new() -> Self {
// The content of this function is the only
// part that is open for change!
// Task is: create a container with `N` elements,
// where every element is initialized with
// `Element::array_initializer`.
}
}
static STATIC_CONTAINER: Container<5> = Container::new();
fn main() {
println!("{:?}", STATIC_CONTAINER);
}
请注意,情况并非如此.
Container { data: [Element(0), Element(1), Element(2), Element(3), Element(4)] }
当然,在拉斯特目前的状态下,这也可能是完全不可能的;尽管我会对此感到非常难过.
我不在乎在Container::new
函数中使用unsafe
,只要它是sound即可.
到目前为止我try 过的东西:
-
它失败是因为它不接受常量泛型数组长度.
impl<const N: usize> Container<N> { pub const fn new() -> Self { const fn element_init(pos: usize) -> Element { Element::array_initializer(pos) } let data: [Element; N] = array_const_fn_init::array_const_fn_init!(element_init; N); Self { data } } }
error: proc macro panicked --> src/main.rs:21:34 | 21 | let data: [Element; N] = array_const_fn_init::array_const_fn_init!(element_init; N); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: message: Expected <usize>, found N
-
MaybeUninit
,以this example为基础impl<const N: usize> Container<N> { pub const fn new() -> Self { use core::mem::MaybeUninit; let mut data: [MaybeUninit<Element>; N] = unsafe { MaybeUninit::uninit().assume_init() }; { // const for's are not stabilized yet, so use a loop let mut i = 0; while i < N { data[i] = MaybeUninit::new(Element::array_initializer(i)); i += 1; } } let data: [Element; N] = unsafe { core::mem::transmute::<[MaybeUninit<Element>; N], [Element; N]>(data) }; Self { data } } }
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> src/main.rs:30:22 | 37 | unsafe { core::mem::transmute::<[MaybeUninit<Element>; N], [Element; N]>(data) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `[MaybeUninit<Element>; N]` (this type does not have a fixed size) = note: target type: `[Element; N]` (this type does not have a fixed size)
这在技术上是无稽之谈,可能是编译器的限制,将来会取消;
[MaybeUninit<Element>; N]
和[Element; N]
的大小肯定是一样的. -
core::intrinsics::transmute_unchecked
个因为我们知道大小是一样的,无论如何用
transmute_unchecked
来做变形.现在我们在
nightly
和feature
的区域,遗憾的是这与我的情况不相容:/#![feature(core_intrinsics)] // ... impl<const N: usize> Container<N> { pub const fn new() -> Self { use core::mem::MaybeUninit; let mut data: [MaybeUninit<Element>; N] = unsafe { MaybeUninit::uninit().assume_init() }; { // const for's are not stabilized yet, so use a loop let mut i = 0; while i < N { data[i] = MaybeUninit::new(Element::array_initializer(i)); i += 1; } } let data: [Element; N] = unsafe { core::intrinsics::transmute_unchecked::<[MaybeUninit<Element>; N], [Element; N]>(data) }; Self { data } } }
这确实给了我们正确的结果,但
feature(core_intrinsics)
可能永远不会被包括在stable
中. -
MaybeUninit::array_assume_init
个这看起来确实有点理智,更接近稳定,但目前它仍然需要
nightly
个编译器和feature
个门.#![feature(maybe_uninit_array_assume_init)] #![feature(const_maybe_uninit_array_assume_init)] // ... impl<const N: usize> Container<N> { pub const fn new() -> Self { use core::mem::MaybeUninit; let mut data: [MaybeUninit<Element>; N] = unsafe { MaybeUninit::uninit().assume_init() }; { // const for's are not stabilized yet, so use a loop let mut i = 0; while i < N { data[i] = MaybeUninit::new(Element::array_initializer(i)); i += 1; } } let data: [Element; N] = unsafe { MaybeUninit::array_assume_init(data) }; Self { data } } }