Union core::mem::MaybeUninit 1.36.0[−][src]
#[repr(transparent)] pub union MaybeUninit<T> { // some fields omitted }
Expand description
包装器类型,用于创建 T
的未初始化实例。
初始化不变式
通常,编译器假定已根据变量类型的要求正确初始化了变量。例如,引用类型的变量必须对齐且非空。 即使在不安全的代码中,这也必须始终保持不变。 结果,将引用类型的变量初始化为零会导致瞬时 undefined behavior,无论引用是否曾经被用来访问内存:
use std::mem::{self, MaybeUninit}; let x: &i32 = unsafe { mem::zeroed() }; // 未定义的行为! ⚠️ // 与 `MaybeUninit<&i32>` 等效的代码: let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // 未定义的行为! ⚠️Run
编译器将其用于各种优化,例如消除运行时检查和优化 enum
布局。
同样,完全未初始化的存储器可以包含任何内容,而 bool
必须始终为 true
或 false
。因此,创建未初始化的 bool
是未定义的行为:
use std::mem::{self, MaybeUninit}; let b: bool = unsafe { mem::uninitialized() }; // 未定义的行为! ⚠️ // 与 `MaybeUninit<bool>` 等效的代码: let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // 未定义的行为! ⚠️Run
此外,未初始化的存储器的特殊之处在于它没有固定的值 (“fixed” 表示 “it won’t change without being written to”)。多次读取相同的未初始化字节会产生不同的结果。 这使得在变量中具有未初始化的数据成为未定义的行为,即使该变量具有整数类型也可以保留任何固定位模式
use std::mem::{self, MaybeUninit}; let x: i32 = unsafe { mem::uninitialized() }; // 未定义的行为! ⚠️ // 与 `MaybeUninit<i32>` 等效的代码: let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // 未定义的行为! ⚠️Run
(请注意,关于未初始化整数的规则尚未最终确定,但是除非被确定,否则建议避免使用它们。)
最重要的是,请记住,大多数类型具有其他不变式,而不仅仅是在类型级别被初始化。
例如,将 1
初始化的 Vec<T>
视为已初始化 (在当前实现下; 这并不构成稳定的保证),因为编译器知道的唯一要求是数据指针必须为非空值。
创建这样的 Vec<T>
不会立即导致未定义的行为,但是在大多数安全操作 (包括丢弃操作) 中都将导致未定义的行为。
Examples
MaybeUninit<T>
用于使不安全的代码能够处理未初始化的数据。
这是向编译器发出的信号,指示此处的数据可能不被初始化:
use std::mem::MaybeUninit; // 创建一个显式未初始化的引用。 // 编译器知道 `MaybeUninit<T>` 内部的数据可能无效,因此不是 UB: let mut x = MaybeUninit::<&i32>::uninit(); // 将其设置为有效值。 x.write(&0); // 提取已初始化的数据 - 仅在正确初始化 `x` 之后 * 才允许这样做! let x = unsafe { x.assume_init() };Run
然后,编译器知道不会对此代码进行任何错误的假设或优化。
您可以认为 MaybeUninit<T>
有点像 Option<T>
,但是没有任何运行时跟踪且没有任何安全检查。
out-pointers
您可以使用 MaybeUninit<T>
来实现 “out-pointers”: 与其从函数中返回数据,还不如将其传递给某个 (uninitialized) 内存的指针以将结果放入其中。
当对调用方来说,控制结果存储在内存中的分配方式很重要并且您希望避免不必要的移动时,这很有用。
use std::mem::MaybeUninit; unsafe fn make_vec(out: *mut Vec<i32>) { // `write` 不会丢弃老的内容,这一点很重要。 out.write(vec![1, 2, 3]); } let mut v = MaybeUninit::uninit(); unsafe { make_vec(v.as_mut_ptr()); } // 现在我们知道 `v` 已初始化! 这也可以确保正确丢弃 vector。 let v = unsafe { v.assume_init() }; assert_eq!(&v, &[1, 2, 3]);Run
逐元素初始化数组
MaybeUninit<T>
可用于按元素初始化大型数组:
use std::mem::{self, MaybeUninit}; let data = { // 创建一个未初始化的 `MaybeUninit` 数组。 // `assume_init` 是安全的,因为我们声称这里已经初始化的类型是一堆 `MaybeUninit`,不需要初始化。 let mut data: [MaybeUninit<Vec<u32>>; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; // 丢弃 `MaybeUninit` 不会执行任何操作。 // 因此,使用裸指针分配代替 `ptr::write` 不会导致旧的未初始化值被丢弃。 // 此外,如果在此循环期间存在 panic,则可能会发生内存泄漏,但不会出现内存安全问题。 for elem in &mut data[..] { elem.write(vec![42]); } // 一切都已初始化。 // 将数组转换为初始化的类型。 unsafe { mem::transmute::<_, [Vec<u32>; 1000]>(data) } }; assert_eq!(&data[0], &[42]);Run
您也可以使用部分初始化的数组,这些数组可以在不稳定的数据结构中找到。
use std::mem::MaybeUninit; use std::ptr; // 创建一个未初始化的 `MaybeUninit` 数组。 // `assume_init` 是安全的,因为我们声称这里已经初始化的类型是一堆 `MaybeUninit`,不需要初始化。 let mut data: [MaybeUninit<String>; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; // 计算我们分配的元素数。 let mut data_len: usize = 0; for elem in &mut data[0..500] { elem.write(String::from("hello")); data_len += 1; } // 对于数组中的每个项,如果我们分配了它,则将其丢弃。 for elem in &mut data[0..data_len] { unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } }Run
逐场初始化结构体
您可以使用 MaybeUninit<T>
和 std::ptr::addr_of_mut
宏来逐字段初始化结构体:
use std::mem::MaybeUninit; use std::ptr::addr_of_mut; #[derive(Debug, PartialEq)] pub struct Foo { name: String, list: Vec<u8>, } let foo = { let mut uninit: MaybeUninit<Foo> = MaybeUninit::uninit(); let ptr = uninit.as_mut_ptr(); // 初始化 `name` 字段 使用 `write` 而不是通过 `=` 赋值,而不是在旧的、未初始化的值上调用 `drop`。 unsafe { addr_of_mut!((*ptr).name).write("Bob".to_string()); } // 初始化 `list` 字段如果此处存在 panic,则 `name` 字段中的 `String` 泄漏。 unsafe { addr_of_mut!((*ptr).list).write(vec![0, 1, 2]); } // 所有字段都已初始化,因此我们调用 `assume_init` 来获取已初始化的 Foo。 unsafe { uninit.assume_init() } }; assert_eq!( foo, Foo { name: "Bob".to_string(), list: vec![0, 1, 2] } );Run
Layout
MaybeUninit<T>
保证具有与 T
相同的大小,对齐方式和 ABI:
use std::mem::{MaybeUninit, size_of, align_of}; assert_eq!(size_of::<MaybeUninit<u64>>(), size_of::<u64>()); assert_eq!(align_of::<MaybeUninit<u64>>(), align_of::<u64>());Run
但是请记住,包含MaybeUninit<T>
的类型不一定是相同的布局。Rust 通常不保证 Foo<T>
的字段具有与 Foo<U>
相同的顺序,即使 T
和 U
具有相同的大小和对齐方式。
此外,由于任何位值对于 MaybeUninit<T>
都是有效的,因此编译器无法应用 non-zero/niche-filling 优化,从而可能导致更大的大小:
assert_eq!(size_of::<Option<bool>>(), 1); assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);Run
如果 T
是 FFI 安全的,则 MaybeUninit<T>
也是如此。
虽然 MaybeUninit
是 #[repr(transparent)]
(表示它保证与 T
相同的大小,对齐方式和 ABI),但是这 不会 更改任何先前的警告。
Option<T>
和 Option<MaybeUninit<T>>
可能仍具有不同的大小,并且包含 T
类型的字段的类型的布局 (和大小) 可能与该字段为 MaybeUninit<T>
的情况不同。
MaybeUninit
是一个是联合类型,并且 union 上的 #[repr(transparent)]
是不稳定的 (请参见 跟踪问题)。
随着时间的推移,对 union 的 #[repr(transparent)]
的确切保证可能会发生变化,并且 MaybeUninit
可能会或可能不会保留 #[repr(transparent)]
。
就是说,MaybeUninit<T>
将总是保证它具有与 T
有相同的大小、对齐方式和 ABI; 只是 MaybeUninit
实现保证的方式可能会演变。
Implementations
创建一个使用给定值初始化的新 MaybeUninit<T>
。
在此函数的返回值上调用 assume_init
是安全的。
注意,丢弃 MaybeUninit<T>
永远不会调用 T 的丢弃代码。
确保 T
在初始化时被丢弃是您的责任。
Example
use std::mem::MaybeUninit; let v: MaybeUninit<Vec<u8>> = MaybeUninit::new(vec![42]);Run
🔬 This is a nightly-only experimental API. (maybe_uninit_uninit_array
)
maybe_uninit_uninit_array
)在未初始化状态下创建 MaybeUninit<T>
项的新数组。
Note: 在 future Rust 版本中,当 Rust 允许 inline const expressions 时,此方法可能变得不必要。
下面的示例可以使用 let mut buf = [const { MaybeUninit::<u8>::uninit() }; 32];
。
Examples
#![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)] use std::mem::MaybeUninit; extern "C" { fn read_into_buffer(ptr: *mut u8, max_len: usize) -> usize; } /// 返回实际读取的 (可能较小的) 数据切片 fn read(buf: &mut [MaybeUninit<u8>]) -> &[u8] { unsafe { let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); MaybeUninit::slice_assume_init_ref(&buf[..len]) } } let mut buf: [MaybeUninit<u8>; 32] = MaybeUninit::uninit_array(); let data = read(&mut buf);Run
在未初始化状态下创建新的 MaybeUninit<T>
,并用 0
字节填充内存。取决于 T
是否已经进行了正确的初始化。
例如,初始化 MaybeUninit<usize>::zeroed()
,但不初始化 MaybeUninit<&'static i32>::zeroed()
,因为引用不能为空。
注意,丢弃 MaybeUninit<T>
永远不会调用 T 的丢弃代码。
确保 T
在初始化时被丢弃是您的责任。
Example
此函数的正确用法: 用零初始化结构体,其中结构体的所有字段都可以将位模式 0 保留为有效值。
use std::mem::MaybeUninit; let x = MaybeUninit::<(u8, bool)>::zeroed(); let x = unsafe { x.assume_init() }; assert_eq!(x, (0, false));Run
该函数的 错误 用法: 当 0
不是该类型的有效位模式时,调用 x.zeroed().assume_init()
:
use std::mem::MaybeUninit; enum NotZero { One = 1, Two = 2 } let x = MaybeUninit::<(u8, NotZero)>::zeroed(); let x = unsafe { x.assume_init() }; // 在一个对中,我们创建一个没有有效判别式的 `NotZero`。 // 这是未定义的行为。⚠️Run
设置 MaybeUninit<T>
的值。
这将覆盖任何先前的值而不将其丢弃,因此请注意不要重复使用此两次,除非您要跳过运行析构函数。
为了您的方便,这也将 self
的内容 (现在已安全初始化) 返回变量引用。
由于内容存储在 MaybeUninit
中,如果 MaybeUninit 离开作用域而没有调用到 assume_init
、assume_init_drop
或类似对象,则不会为内部数据运行析构函数。
接收这个函数返回的附属引用引用的代码需要记住这一点。
Rust 的安全模型认为泄漏是安全的,但它们通常仍然是不可取的。
话虽这么说,但借用引用与其他任何一个借用引用一样,因此为其赋予新的值将摒弃旧的内容。
Examples
正确使用此方法:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<Vec<u8>>::uninit(); { let hello = x.write((&b"Hello, world!").to_vec()); // 设置 hello 不会预先分配,但不会泄漏它们 *hello = (&b"Hello").to_vec(); hello[0] = 'h' as u8; } // x 现在初始化: let s = unsafe { x.assume_init() }; assert_eq!(b"hello", s.as_slice());Run
该方法的这种用法会导致泄漏:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<String>::uninit(); x.write("Hello".to_string()); // 这会泄漏包含的字符串: x.write("hello".to_string()); // x 现在初始化: let s = unsafe { x.assume_init() };Run
这种方法可以用来避免在某些情况下不安全。下面的例子展示了一个固定大小的 arena 实现的一部分,它提供了固定的引用。
有了 write
,我们就可以避免通过裸指针路径来写:
#![feature(maybe_uninit_extra)] use core::pin::Pin; use core::mem::MaybeUninit; struct PinArena<T> { memory: Box<[MaybeUninit<T>]>, len: usize, } impl <T> PinArena<T> { pub fn capacity(&self) -> usize { self.memory.len() } pub fn push(&mut self, val: T) -> Pin<&mut T> { if self.len >= self.capacity() { panic!("Attempted to push to a full pin arena!"); } let ref_ = self.memory[self.len].write(val); self.len += 1; unsafe { Pin::new_unchecked(ref_) } } }Run
获取指向包含值的指针。
除非初始化 MaybeUninit<T>
,否则从该指针读取或将其转换为 quot 是未定义的行为。
写入该指针 (non-transitively) 指向的内存是未定义的行为 (UnsafeCell<T>
内部除外)。
Examples
正确使用此方法:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<Vec<u32>>::uninit(); x.write(vec![0, 1, 2]); // 在 `MaybeUninit<T>` 中创建引用。可以,因为我们已将其初始化。 let x_vec = unsafe { &*x.as_ptr() }; assert_eq!(x_vec.len(), 3);Run
这个方法的错误用法:
use std::mem::MaybeUninit; let x = MaybeUninit::<Vec<u32>>::uninit(); let x_vec = unsafe { &*x.as_ptr() }; // 我们创建了对未初始化的 vector 的引用! 这是未定义的行为。⚠️Run
(请注意,围绕未初始化数据引用的规则尚未最终确定,但是除非被确定,否则建议避免使用它们。)
获取指向包含值的可变指针。
除非初始化 MaybeUninit<T>
,否则从该指针读取或将其转换为 quot 是未定义的行为。
Examples
正确使用此方法:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<Vec<u32>>::uninit(); x.write(vec![0, 1, 2]); // 在 `MaybeUninit<Vec<u32>>` 中创建引用。 // 可以,因为我们已将其初始化。 let x_vec = unsafe { &mut *x.as_mut_ptr() }; x_vec.push(3); assert_eq!(x_vec.len(), 4);Run
这个方法的错误用法:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<Vec<u32>>::uninit(); let x_vec = unsafe { &mut *x.as_mut_ptr() }; // 我们创建了对未初始化的 vector 的引用! 这是未定义的行为。⚠️Run
(请注意,围绕未初始化数据引用的规则尚未最终确定,但是除非被确定,否则建议避免使用它们。)
从 MaybeUninit<T>
容器中提取值。这是确保数据将被丢弃的好方法,因为生成的 T
受到通常的丢弃处理。
Safety
取决于调用方,以确保 MaybeUninit<T>
确实处于初始化状态。在内容尚未完全初始化时调用此方法会立即导致未定义的行为。
类型级文档 中包含了有关此初始化不可变变量的更多信息。
最重要的是,请记住,大多数类型具有其他不变式,而不仅仅是在类型级别被初始化。
例如,将 1
初始化的 Vec<T>
视为已初始化 (在当前实现下; 这并不构成稳定的保证),因为编译器知道的唯一要求是数据指针必须为非空值。
创建这样的 Vec<T>
不会立即导致未定义的行为,但是在大多数安全操作 (包括丢弃操作) 中都将导致未定义的行为。
Examples
正确使用此方法:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<bool>::uninit(); x.write(true); let x_init = unsafe { x.assume_init() }; assert_eq!(x_init, true);Run
这个方法的错误用法:
use std::mem::MaybeUninit; let x = MaybeUninit::<Vec<u32>>::uninit(); let x_init = unsafe { x.assume_init() }; // `x` 尚未初始化,因此这最后一行导致未定义的行为。⚠️Run
从 MaybeUninit<T>
容器中读取值。结果 T
受通常的 drop 处理影响。
只要有可能,最好改用 assume_init
,这样可以防止重复 MaybeUninit<T>
的内容。
Safety
取决于调用方,以确保 MaybeUninit<T>
确实处于初始化状态。在内容尚未完全初始化时调用此方法会导致未定义的行为。
类型级文档 中包含了有关此初始化不可变变量的更多信息。
此外,类似于 ptr::read
函数,该函数创建内容的按位副本,无论所包含的类型是否实现 Copy
trait。
使用数据的多个副本时 (通过多次调用 assume_init_read
,或先调用 assume_init_read
,然后再调用 assume_init
),您有责任确保确实可以复制数据。
Examples
正确使用此方法:
#![feature(maybe_uninit_extra)] use std::mem::MaybeUninit; let mut x = MaybeUninit::<u32>::uninit(); x.write(13); let x1 = unsafe { x.assume_init_read() }; // `u32` 是 `Copy`,因此我们可能会多次读取。 let x2 = unsafe { x.assume_init_read() }; assert_eq!(x1, x2); let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit(); x.write(None); let x1 = unsafe { x.assume_init_read() }; // 复制 `None` 值是可以的,因此我们可能会多次读取。 let x2 = unsafe { x.assume_init_read() }; assert_eq!(x1, x2);Run
这个方法的错误用法:
#![feature(maybe_uninit_extra)] use std::mem::MaybeUninit; let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit(); x.write(Some(vec![0, 1, 2])); let x1 = unsafe { x.assume_init_read() }; let x2 = unsafe { x.assume_init_read() }; // 现在,我们创建了同一 vector 的两个副本,当它们都被丢弃时,将导致双重释放!Run
将包含的值放置到位。
如果您拥有 MaybeUninit
,您也可以使用 assume_init
作为替代。
Safety
取决于调用方,以确保 MaybeUninit<T>
确实处于初始化状态。
在内容尚未完全初始化时调用此方法会导致未定义的行为。
最重要的是,必须满足类型 T
的所有其他不可变变量,因为 T
(或其成员) 的 Drop
实现可能依赖于此。
例如,将 Vec<T>
设置为无效但非空的地址使其初始化 (在当前实现下;
这并不构成稳定的保证),因为编译器知道的唯一要求是数据指针必须非空。
但是,丢弃这样的 Vec<T>
会导致不确定的行为。
获取对包含值的共享引用。
当我们要访问已初始化但没有 MaybeUninit
所有权 (防止使用 .assume_init()
) 的 MaybeUninit
时,这很有用。
Safety
在内容尚未完全初始化时调用此方法会导致未定义的行为: 取决于调用方,以确保 MaybeUninit<T>
确实处于初始化状态。
Examples
正确使用此方法:
use std::mem::MaybeUninit; let mut x = MaybeUninit::<Vec<u32>>::uninit(); // 初始化 `x`: x.write(vec![1, 2, 3]); // 现在已知我们的 `MaybeUninit<_>` 已初始化,可以创建对其的共享引用: let x: &Vec<u32> = unsafe { // SAFETY: `x` 已初始化。 x.assume_init_ref() }; assert_eq!(x, &vec![1, 2, 3]);Run
这个方法的错误用法:
use std::mem::MaybeUninit; let x = MaybeUninit::<Vec<u32>>::uninit(); let x_vec: &Vec<u32> = unsafe { x.assume_init_ref() }; // 我们创建了对未初始化的 vector 的引用! 这是未定义的行为。⚠️Run
use std::{cell::Cell, mem::MaybeUninit}; let b = MaybeUninit::<Cell<bool>>::uninit(); // 使用 `Cell::set` 初始化 `MaybeUninit`: unsafe { b.assume_init_ref().set(true); // ^^^^^^^^^^^^^^^ // 引用未初始化的 `Cell<bool>`: UB! }Run
获取所包含值的可变 (unique) 引用。
当我们要访问已初始化但没有 MaybeUninit
所有权 (防止使用 .assume_init()
) 的 MaybeUninit
时,这很有用。
Safety
在内容尚未完全初始化时调用此方法会导致未定义的行为: 取决于调用方,以确保 MaybeUninit<T>
确实处于初始化状态。
例如,.assume_init_mut()
不能用于初始化 MaybeUninit
。
Examples
正确使用此方法:
use std::mem::MaybeUninit; extern "C" { /// 初始化所有输入缓冲区的字节。 fn initialize_buffer(buf: *mut [u8; 1024]); } let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // 初始化 `buf`: unsafe { initialize_buffer(buf.as_mut_ptr()); } // 现在我们知道 `buf` 已被初始化,因此我们可以对其进行 `.assume_init()`。 // 但是,使用 `.assume_init()` 可能会触发 1024 字节的 `memcpy`。 // 为了断言我们的缓冲区已经初始化而不复制它,我们将 `&mut MaybeUninit<[u8; 1024]>` 升级为 `&mut [u8; 1024]`: let buf: &mut [u8; 1024] = unsafe { // SAFETY: `buf` 已初始化。 buf.assume_init_mut() }; // 现在我们可以将 `buf` 用作普通切片: buf.sort_unstable(); assert!( buf.windows(2).all(|pair| pair[0] <= pair[1]), "buffer is sorted", );Run
这个方法的错误用法:
您不能使用 .assume_init_mut()
初始化值:
use std::mem::MaybeUninit; let mut b = MaybeUninit::<bool>::uninit(); unsafe { *b.assume_init_mut() = true; // 我们已经创建了 (mutable) 引用未初始化的 `bool`! // 这是未定义的行为。⚠️ }Run
例如,您不能 Read
进入未初始化的缓冲区:
use std::{io, mem::MaybeUninit}; fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> { let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); reader.read_exact(unsafe { buffer.assume_init_mut() })?; // ^^^^^^^^^^^^^^^^^^^^^^^^ // (mutable) 引用未初始化的内存! // 这是未定义的行为。 Ok(unsafe { buffer.assume_init() }) }Run
也不能使用直接字段访问来进行逐字段逐步初始化:
use std::{mem::MaybeUninit, ptr}; struct Foo { a: u32, b: u8, } let foo: Foo = unsafe { let mut foo = MaybeUninit::<Foo>::uninit(); ptr::write(&mut foo.assume_init_mut().a as *mut u32, 1337); // ^^^^^^^^^^^^^^^^^^^^^ // (mutable) 引用未初始化的内存! // 这是未定义的行为。 ptr::write(&mut foo.assume_init_mut().b as *mut u8, 42); // ^^^^^^^^^^^^^^^^^^^^^ // (mutable) 引用未初始化的内存! // 这是未定义的行为。 foo.assume_init() };Run
从 MaybeUninit
容器数组中提取值。
Safety
调用方有责任保证数组的所有元素都处于初始化状态。
Examples
#![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_array_assume_init)] use std::mem::MaybeUninit; let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array(); array[0].write(0); array[1].write(1); array[2].write(2); // SAFETY: 现在安全了,因为我们初始化了所有元素 let array = unsafe { MaybeUninit::array_assume_init(array) }; assert_eq!(array, [0, 1, 2]);Run
假设所有元素都已初始化,请对其进行切片。
Safety
取决于调用方,以确保 MaybeUninit<T>
元素确实处于初始化状态。
在内容尚未完全初始化时调用此方法会导致未定义的行为。
有关更多详细信息和示例,请参见 assume_init_ref
。
假设所有元素都已初始化,请为其获取可变切片。
Safety
取决于调用方,以确保 MaybeUninit<T>
元素确实处于初始化状态。
在内容尚未完全初始化时调用此方法会导致未定义的行为。
有关更多详细信息和示例,请参见 assume_init_mut
。
获取一个指向数组第一个元素的指针。
获取指向数组第一个元素的可变指针。
pub fn write_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T] where
T: Copy,
[src]
pub fn write_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T] where
T: Copy,
[src]从 src
复制元素,将 this
现在初始化的内容返回给 this
的资源引用。
如果 T
未实现 Copy
,请使用 write_slice_cloned
这类似于 slice::copy_from_slice
。
Panics
如果两个切片的长度不同,则此函数将为 panic。
Examples
#![feature(maybe_uninit_write_slice)] use std::mem::MaybeUninit; let mut dst = [MaybeUninit::uninit(); 32]; let src = [0; 32]; let init = MaybeUninit::write_slice(&mut dst, &src); assert_eq!(init, src);Run
#![feature(maybe_uninit_write_slice, vec_spare_capacity)] use std::mem::MaybeUninit; let mut vec = Vec::with_capacity(32); let src = [0; 16]; MaybeUninit::write_slice(&mut vec.spare_capacity_mut()[..src.len()], &src); // SAFETY: 我们刚刚将 len 的所有元素复制到了备用容量中,vec 的第一个 src.len() 元素现在有效。 unsafe { vec.set_len(src.len()); } assert_eq!(vec, src);Run
pub fn write_slice_cloned<'a>(
this: &'a mut [MaybeUninit<T>],
src: &[T]
) -> &'a mut [T] where
T: Clone,
[src]
pub fn write_slice_cloned<'a>(
this: &'a mut [MaybeUninit<T>],
src: &[T]
) -> &'a mut [T] where
T: Clone,
[src]将元素从 src
克隆到 this
,返回一个资源引用引用到 this
现在初始化的内容。
任何已经初始化的元素都不会被丢弃。
如果 T
实现 Copy
,请使用 write_slice
这类似于 slice::clone_from_slice
,但不会丢弃现有元素。
Panics
如果两个切片的长度不同,或者 Clone
panics 的实现,则此函数将为 panic。
如果存在 panic,将丢弃已经克隆的元素。
Examples
#![feature(maybe_uninit_write_slice)] use std::mem::MaybeUninit; let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()]; let init = MaybeUninit::write_slice_cloned(&mut dst, &src); assert_eq!(init, src);Run
#![feature(maybe_uninit_write_slice, vec_spare_capacity)] use std::mem::MaybeUninit; let mut vec = Vec::with_capacity(32); let src = ["rust", "is", "a", "pretty", "cool", "language"]; MaybeUninit::write_slice_cloned(&mut vec.spare_capacity_mut()[..src.len()], &src); // SAFETY: 我们刚刚将 len 的所有元素克隆到了备用容量中,vec 的第一个 src.len() 元素现在有效。 unsafe { vec.set_len(src.len()); } assert_eq!(vec, src);Run