如果该类型是泛型类型参数,如何创建零大小类型的实例?
(!) 我对“The Rustonomicon”9.10 提供的答案不感兴趣。处理零大小类型、片段Some(ptr::read(NonNull::<T>::dangling().as_ptr()))。
例如
fn get<T>() -> Option<T>
if size_of::<T>() == 0 { // If the type parameter T is a zero-sized type
return Some< ??? > // then return the instance of that type.
// Otherwise return something different.
Run Code Online (Sandbox Code Playgroud)
???我可以在上面的代码中放置什么来代替?
理想情况下,我希望此代码适用于作为 传递的任何零大小类型T,
Defaultstruct Zst;, struct Zst{}),())enum Zst;, enum Zst { TheOnlyValue })[u8; 0])最终我需要以下内容:
impl<T> Iterator for RawIter<T> { // Some generic code.
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if size_of::<T>() == 0 { // If the type parameter T is a zero-sized type
Some< ??? > // then return the instance of that type.
Run Code Online (Sandbox Code Playgroud)
更正
Some(ptr::read(NonNull::<T>::dangling().as_ptr()))(和*std::ptr::NonNull::<T>::dangling().as_ptr())似乎以两种方式导致未定义的行为,请参阅此问题项 3.B (dangling ptr deref) 和 4 (uninit mem read)。std::mem::MaybeUninit::<T>::uninit().assume_init()有导致未定义行为的风险(uninit mem read),请参阅Should_init() 安全性和此问题第 4 项std::mem::zeroed::<T>()获胜,因为它比它的同义词短std::mem::MaybeUninit::<T>::zeroed().assume_init()。构建 ZST 有多种可能的方法:
std::mem::zeroed::<T>()std::mem::MaybeUninit::<T>::uninit().assume_init()std::mem::MaybeUninit::<T>::zeroed().assume_init()*std::ptr::NonNull::<T>::dangling().as_ptr()ETC..
还有一个已接受的 API 更改提案,该conjure_zst()提案将成为构造 ZST 的方式,但在撰写本文时尚未实现。
但是,请注意,构造任意 ZST(或任何类型)是不合理的,因为类型可以携带不变量。例如,下面的代码是完全正确的:
pub struct ImpossibleToConstruct(());
impl ImpossibleToConstruct {
pub fn cause_ub(self) {
unsafe { std::hint::unreachable_unchecked() };
}
}
Run Code Online (Sandbox Code Playgroud)
但如果你提供一个get()函数来构造任意 ZST,用户就可以在安全代码中引发 UB:
get::<ImpossibleToConstruct>().cause_ub();
Run Code Online (Sandbox Code Playgroud)
诚然,这个例子相当愚蠢,但是带有不变量的 ZST 有很多用例。
因此,如果你想提供这样的功能,它必须是unsafe(上面提到的将来应该填补的角色conjure_zst())或受某些约束unsafe trait SafeToConjureZst(你可以提供一个#[derive]for,以使用户代码完全安全,但在这一点上你最好使用bytemuck::Podwithbytemuck::cast::<(), T>(())来安全地完成这一切)。
| 归档时间: |
|
| 查看次数: |
170 次 |
| 最近记录: |