NonNUll
NonNull<T>
实现类似可变指针 *mut T
的功能, 同时有以下区别:
- 指针非空 (non-zero)
- 类型协变 covariant
它在标准库里是这样定义的:
#[repr(transparent)]
pub struct NonNull<T: ?Sized> {
pointer: *const T,
}
从定义中可以看到, 它只是存储了一个原始指针, 并没有所有权相关的.
NonNull<T>
没有实现 Send
以及 Sync
traits:
/// `NonNull` pointers are not `Send` because the data they reference may be aliased.
impl<T: ?Sized> ! Send for NonNull<T> {}
/// `NonNull` pointers are not `Sync` because the data they reference may be aliased.
impl<T: ?Sized> ! Sync for NonNull<T> {}
协变性 Covariance
其它类型, 比如 Box<T>
, Rc<T>
, Arc<T>
, Vec<T>
, LinkedList<T>
, 都有协变性.
是这些范型类拥有的属性:
- 如果
T
是U
的子类, 意味着F<T>
是F<u>
的子类, 则F<T>
对T
是协变的 (covariant) - 如果
T
是U
的子类, 意味着F<U>
是F<T>
的子类, 则F<T>
对T
是协变的 (covariant) - 否则,
F<T>
对T
是不变的 (invariant)
内存布局
因为有了空指针优化(null pointer optimization),
NoneNull<T>
与 Option<NonNull<T>>
拥有一样的内存大小以及对齐方式.
#![allow(unused)] fn main() { use std::ptr::NonNull; use std::mem::{align_of, size_of}; assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>()); assert_eq!(align_of::<NonNull<i16>>(), align_of::<Option<NonNull<i16>>>()); assert_eq!(size_of::<NonNull<str>>(), size_of::<Option<NonNull<str>>>()); assert_eq!(align_of::<NonNull<str>>(), align_of::<Option<NonNull<str>>>()); }
常用方法
new()
,new_unchecked()
, 创建新的NonNull
对象as_ptr()
得到*mut T
指针as_ref()
得到只读引用as_mut()
得到可变更引用
use std::ptr::NonNull; fn main() { let mut x = 1_u32; let mut ptr = NonNull::new(&mut x as *mut u32).expect("Invalid pointer"); unsafe { *ptr.as_ptr() += 1; } let x_value = unsafe { *ptr.as_ptr() }; assert_eq!(x_value, 2); assert_eq!(x, 2); let x_ref = unsafe { ptr.as_mut() }; *x_ref += 1; assert_eq!(x, 3); }
上面的代码片段, 其栈上的内存布局如下图所示: