Primitive Type pointer
1.0.0 ·Expand description
原始的、不安全的指针 *const T
和 *mut T
。
在 Rust 中使用裸指针并不常见,通常仅限于几种模式。
裸指针可以是未对齐的或 null
。但是,当解引用裸指针 (使用 *
运算符) 时,它必须为非 null 并对齐。
使用 *ptr = data
通过裸指针存储会在旧值上调用 drop
,因此,如果该类型具有 drop glue 并且尚未初始化内存,则必须使用 write
; 否则,将在未初始化的内存上调用 drop
。
使用 null
和 null_mut
函数创建空指针,并使用 *const T
和 *mut T
类型的 is_null
方法检查空值。
*const T
和 *mut T
类型还定义了用于指针数学的 offset
方法。
创建裸指针的常用方法
1. 强制引用 (&T
) 或可变引用 (&mut T
)。
let my_num: i32 = 10;
let my_num_ptr: *const i32 = &my_num;
let mut my_speed: i32 = 88;
let my_speed_ptr: *mut i32 = &mut my_speed;
Run要获得指向 boxed 值的指针,请解引用 box:
let my_num: Box<i32> = Box::new(10);
let my_num_ptr: *const i32 = &*my_num;
let mut my_speed: Box<i32> = Box::new(88);
let my_speed_ptr: *mut i32 = &mut *my_speed;
Run这不会获得原始分配的所有权,并且以后不需要任何资源管理,但是您一定不能在其生命周期之后使用该指针。
2. 消费 box (Box<T>
)。
into_raw
函数消费 box 并返回裸指针。它不会销毁 T
或释放任何内存。
let my_speed: Box<i32> = Box::new(88);
let my_speed: *mut i32 = Box::into_raw(my_speed);
// 通过拥有原始 `Box<T>` 的所有权,我们有义务稍后将其放在一起销毁。
unsafe {
drop(Box::from_raw(my_speed));
}
Run请注意,此处对 drop
的调用是为了清楚起见 - 表示我们已经完成了给定值的操作,应将其销毁。
3. 使用 ptr::addr_of!
创建它
您可以使用宏 ptr::addr_of!
(对于 *const T
) 和 ptr::addr_of_mut!
(对于 *mut T
),而不是强制引用裸指针。
这些宏允许您创建裸指针指向您无法创建引用的字段 (不会导致未定义的行为),例如未对齐的字段。
如果涉及包装的结构或未初始化的内存,这可能是必要的。
#[derive(Debug, Default, Copy, Clone)]
#[repr(C, packed)]
struct S {
aligned: u8,
unaligned: u32,
}
let s = S::default();
let p = std::ptr::addr_of!(s.unaligned); // 不允许强制转换
Run4. 从 C 获取它。
#[allow(unused_extern_crates)]
extern crate libc;
use std::mem;
unsafe {
let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
if my_num.is_null() {
panic!("failed to allocate memory");
}
libc::free(my_num as *mut libc::c_void);
}
Run通常,您实际上不会使用 Rust 中的 malloc
和 free
,但是 C API 通常会发出很多指针,因此 Rust 中的裸指针常见来源。
Implementations§
source§impl<T> *const [T]
impl<T> *const [T]
const: unstable · sourcepub fn len(self) -> usize
🔬This is a nightly-only experimental API. (slice_ptr_len
#71146)
pub fn len(self) -> usize
slice_ptr_len
#71146)const: unstable · sourcepub fn as_ptr(self) -> *const T
🔬This is a nightly-only experimental API. (slice_ptr_get
#74265)
pub fn as_ptr(self) -> *const T
slice_ptr_get
#74265)sourcepub unsafe fn get_unchecked<I>(
self,
index: I
) -> *const <I as SliceIndex<[T]>>::Outputwhere
I: SliceIndex<[T]>,
🔬This is a nightly-only experimental API. (slice_ptr_get
#74265)
pub unsafe fn get_unchecked<I>( self, index: I ) -> *const <I as SliceIndex<[T]>>::Outputwhere I: SliceIndex<[T]>,
slice_ptr_get
#74265)const: unstable · sourcepub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>
🔬This is a nightly-only experimental API. (ptr_as_uninit
#75402)
pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>
ptr_as_uninit
#75402)如果指针为空,则返回 None
,否则返回共享切片到 Some
中包装的值。
与 as_ref
相比,这不需要将该值初始化。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须为 有效 的,才能读取许多字节的
ptr.len() * mem::size_of::<T>()
,并且必须正确对齐。这尤其意味着:-
整个内存范围必须包含在单个 分配对象 内! 切片永远不能跨越多个分配的对象。
-
即使对于零长度的切片,指针也必须对齐。 这样做的一个原因是,枚举布局优化可能依赖于对齐的引用 (包括任何长度的切片) 和非空值,以将它们与其他数据区分开。
您可以使用
NonNull::dangling()
获得可用作零长度切片的data
的指针。 -
-
切片的总大小
ptr.len() * mem::size_of::<T>()
不能大于isize::MAX
。 请参见pointer::offset
的安全文档。 -
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能发生可变 (UnsafeCell
内部除外)。
即使未使用此方法的结果也是如此!
另请参见 slice::from_raw_parts
。
source§impl<T> *const Twhere
T: ?Sized,
impl<T> *const Twhere T: ?Sized,
const: unstable · sourcepub fn is_null(self) -> bool
pub fn is_null(self) -> bool
如果指针为空,则返回 true
。
请注意,未定义大小的类型具有许多可能的空指针,因为仅考虑原始数据指针,而不考虑其长度,vtable 等。 因此,两个为空的指针可能仍不能相互比较相等。
常量评估期间的行为
在 const 评估期间使用此函数时,对于在运行时结果为空的指针,它可能返回 false
。
具体来说,当指向某个内存的指针超出其范围的偏移量 (使结果指针为空) 时,函数仍将返回 false
。
CTFE 无法知道该内存的绝对位置,因此我们无法确定指针是否为空。
Examples
let s: &str = "Follow the rabbit";
let ptr: *const u8 = s.as_ptr();
assert!(!ptr.is_null());
Runconst: unstable · sourcepub fn with_metadata_of<U>(self, meta: *const U) -> *const Uwhere
U: ?Sized,
🔬This is a nightly-only experimental API. (set_ptr_value
#75091)
pub fn with_metadata_of<U>(self, meta: *const U) -> *const Uwhere U: ?Sized,
set_ptr_value
#75091)在另一种类型的新指针中使用指针值。
如果 meta
是指向未定义大小类型的 (fat) 指针,此操作将忽略指针部分,而对于指向大小类型的 (thin) 指针,这与简单强制转换具有相同的效果。
生成的指针将具有 self
的来源,即,对于胖指针,此操作在语义上与创建数据指针值为 self
但元数据为 meta
的新胖指针相同。
Examples
此函数主要用于允许对潜在的胖指针进行按字节指针算术运算:
#![feature(set_ptr_value)]
let arr: [i32; 3] = [1, 2, 3];
let mut ptr = arr.as_ptr() as *const dyn Debug;
let thin = ptr as *const u8;
unsafe {
ptr = thin.add(8).with_metadata_of(ptr);
println!("{:?}", &*ptr); // 将打印 "3"
}
Run1.65.0 (const: 1.65.0) · sourcepub const fn cast_mut(self) -> *mut T
pub const fn cast_mut(self) -> *mut T
更改常量而不更改类型。
这比 as
安全一点,因为如果重构代码,它不会默默地改变类型。
sourcepub fn to_bits(self) -> usize
👎Deprecated since 1.67.0: replaced by the expose_addr
method, or update your code to follow the strict provenance rules using its APIs🔬This is a nightly-only experimental API. (ptr_to_from_bits
#91126)
pub fn to_bits(self) -> usize
expose_addr
method, or update your code to follow the strict provenance rules using its APIsptr_to_from_bits
#91126)将指针强制转换为原始位。
这等效于 as usize
,但更具体以增强可读性。
相反的方法是 from_bits
。
特别是,*p as usize
和 p as usize
都会编译指向数字类型的指针,但做的事情却截然不同,因此使用它有助于强调读取位是有意的。
Examples
#![feature(ptr_to_from_bits)]
let array = [13, 42];
let p0: *const i32 = &array[0];
assert_eq!(<*const _>::from_bits(p0.to_bits()), p0);
let p1: *const i32 = &array[1];
assert_eq!(p1.to_bits() - p0.to_bits(), 4);
Runsourcepub fn from_bits(bits: usize) -> *const T
👎Deprecated since 1.67.0: replaced by the ptr::from_exposed_addr
function, or update your code to follow the strict provenance rules using its APIs🔬This is a nightly-only experimental API. (ptr_to_from_bits
#91126)
pub fn from_bits(bits: usize) -> *const T
ptr::from_exposed_addr
function, or update your code to follow the strict provenance rules using its APIsptr_to_from_bits
#91126)sourcepub fn addr(self) -> usize
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn addr(self) -> usize
strict_provenance
#95228)获取指针的 “address” 部分。
这类似于 self as usize
,它在语义上丢弃了provenance 和address-space 信息。
但是,与 self as usize
不同,将返回的地址转换回指针会产生 invalid
,这对于解引用来说是未定义的行为。
要正确恢复丢失的信息并获得可解引用的指针,请使用 with_addr
或 map_addr
。
如果由于无法保留具有所需出处的指针而无法使用这些 API,请改用 expose_addr
和 from_exposed_addr
。
但是,请注意,这会降低您的代码的可移植性,并且不太适合用于检查是否符合 Rust 内存模型的工具。
在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。 需要在指针中存储附加信息的平台可以执行表示的改变,以产生仅包含指针的地址部分的值。 这意味着什么取决于平台来定义。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,因此可能会在 future 中发生变化 (包括可能削弱这一点,使其完全等同于 self as usize
)。
有关详细信息,请参见 [模块文档。
sourcepub fn expose_addr(self) -> usize
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn expose_addr(self) -> usize
strict_provenance
#95228)获取指针的 “address” 部分,并暴露 “provenance” 部分,以便将来在 from_exposed_addr
中使用。
这相当于 self as usize
,它在语义上丢弃了 provenance 和 address-space 信息。
此外,这 (如 as
cast 一样) 具有将出处标记为 ‘exposed’ 的隐式副作用,因此在支持它的平台上,您可以稍后调用 from_exposed_addr
来重构原始指针,包括其出处。
(如果需要,重建地址空间信息是您的责任。)
使用这种方法意味着代码没有遵循严格的出处规则。
支持 from_exposed_addr
会使规范和推理复杂化,并且可能不受帮助您与 Rust 内存模型保持一致的工具的支持,因此建议尽可能使用 addr
。
在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。
需要在指针中存储附加信息的平台可能不支持此操作,因为 from_exposed_addr
工作所需的 ‘expose’ 副作用通常不可用。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档。
sourcepub fn with_addr(self, addr: usize) -> *const T
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn with_addr(self, addr: usize) -> *const T
strict_provenance
#95228)使用给定地址创建一个新指针。
这执行与 addr as ptr
强制转换相同的操作,但将 self
的 address-space 和 provenance 复制到新指针。
这使我们能够动态地保存和传播这些重要信息,而这在其他情况下使用一元强制转换是不可能的。
这相当于使用 wrapping_offset
将 self
偏移到给定地址,因此具有所有相同的功能和限制。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档。
sourcepub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> *const T
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> *const T
strict_provenance
#95228)const: unstable · sourcepub fn to_raw_parts(self) -> (*const (), <T as Pointee>::Metadata)
🔬This is a nightly-only experimental API. (ptr_metadata
#81513)
pub fn to_raw_parts(self) -> (*const (), <T as Pointee>::Metadata)
ptr_metadata
#81513)将指针 (可能是宽指针) 分解为其地址和元数据组件。
以后可以使用 from_raw_parts
重建指针。
1.9.0 (const: unstable) · sourcepub unsafe fn as_ref<'a>(self) -> Option<&'a T>
pub unsafe fn as_ref<'a>(self) -> Option<&'a T>
如果指针为空,则返回 None
,否则返回 Some
中包装的值的共享引用。如果该值可能未初始化,则必须改用 as_uninit_ref
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
指针必须指向
T
的初始化实例。 -
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能发生可变 (UnsafeCell
内部除外)。
即使未使用此方法的结果也是如此! (关于初始化的部分尚未完全决定,但是直到确定之前,唯一安全的方法是确保它们确实被初始化。)
Examples
let ptr: *const u8 = &10u8 as *const u8;
unsafe {
if let Some(val_back) = ptr.as_ref() {
println!("We got back the value: {val_back}!");
}
}
Run空未经检查的版本
如果确定指针永远不会为空,并且正在寻找某种返回 &T
而不是 Option<&T>
的 as_ref_unchecked
,请知道您可以直接引用该指针。
let ptr: *const u8 = &10u8 as *const u8;
unsafe {
let val_back = &*ptr;
println!("We got back the value: {val_back}!");
}
Runconst: unstable · sourcepub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
🔬This is a nightly-only experimental API. (ptr_as_uninit
#75402)
pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
ptr_as_uninit
#75402)如果指针为空,则返回 None
,否则返回 Some
中包装的值的共享引用。
与 as_ref
相比,这不需要将该值初始化。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。特别是,当这个引用存在时,指针指向的内存不能发生可变 (
UnsafeCell
内部除外)。
即使未使用此方法的结果也是如此!
Examples
#![feature(ptr_as_uninit)]
let ptr: *const u8 = &10u8 as *const u8;
unsafe {
if let Some(val_back) = ptr.as_uninit_ref() {
println!("We got back the value: {}!", val_back.assume_init());
}
}
Runconst: 1.61.0 · sourcepub const unsafe fn offset(self, count: isize) -> *const T
pub const unsafe fn offset(self, count: isize) -> *const T
计算与指针的偏移量。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度总和 (以字节为单位) 必须适合于 usize。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_offset
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
let s: &str = "123";
let ptr: *const u8 = s.as_ptr();
unsafe {
println!("{}", *ptr.offset(1) as char);
println!("{}", *ptr.offset(2) as char);
}
Runconst: unstable · sourcepub unsafe fn byte_offset(self, count: isize) -> *const T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_offset(self, count: isize) -> *const T
pointer_byte_offsets
#96283)计算与指针的偏移量 (以字节为单位)。
count
以 字节 为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 offset。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.16.0 (const: 1.61.0) · sourcepub const fn wrapping_offset(self, count: isize) -> *const T
pub const fn wrapping_offset(self, count: isize) -> *const T
使用换行算法计算与指针的偏移量。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
此操作本身始终是安全的,但使用结果指针则不安全。
结果指针 “remembers” 是 self
指向的 分配对象; 它不得用于读取或写入其他分配的对象。
换句话说,即使我们假设 T
的大小为 1
并且没有溢出,let z = x.wrapping_offset((y as isize) - (x as isize))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 offset
相比,此方法从根本上延迟了留在同一分配对象内的需求: offset
是跨越对象边界时的立即未定义行为; wrapping_offset
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
offset
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
// 使用裸指针以两个元素为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_offset(6);
// 此循环打印 "1, 3, 5, "
while ptr != end_rounded_up {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_offset(step);
}
Runconst: unstable · sourcepub fn wrapping_byte_offset(self, count: isize) -> *const T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub fn wrapping_byte_offset(self, count: isize) -> *const T
pointer_byte_offsets
#96283)使用环绕算法计算与指针的偏移量 (以字节为单位)。
count
以 字节 为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 wrapping_offset。
请参见该方法以获取文档。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
sourcepub fn mask(self, mask: usize) -> *const T
🔬This is a nightly-only experimental API. (ptr_mask
#98290)
pub fn mask(self, mask: usize) -> *const T
ptr_mask
#98290)根据掩码屏蔽指针的位。
这对 ptr.map_addr(|a| a & mask)
来说很方便。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
Examples
#![feature(ptr_mask, strict_provenance)]
let v = 17_u32;
let ptr: *const u32 = &v;
// `u32` 是 4 字节对齐的,这意味着低 2 位总是 0.
let tag_mask = 0b11;
let ptr_mask = !tag_mask;
// 我们可以在这些低位存储一些东西
let tagged_ptr = ptr.map_addr(|a| a | 0b10);
// 取回 "tag"
let tag = tagged_ptr.addr() & tag_mask;
assert_eq!(tag, 0b10);
// 注意 `tagged_ptr` 是未对齐的,它是 UB 读取它。
// 要获得原始指针 `mask` 可以使用:
let masked_ptr = tagged_ptr.mask(ptr_mask);
assert_eq!(unsafe { *masked_ptr }, 17);
Run1.47.0 (const: 1.65.0) · sourcepub const unsafe fn offset_from(self, origin: *const T) -> isize
pub const unsafe fn offset_from(self, origin: *const T) -> isize
计算两个指针之间的距离。返回值以 T 为单位: 以字节为单位的距离除以 mem::size_of::<T>()
。
该函数是 offset
的逆函数。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和其他指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
两个指针必须是指向同一对象的指针的 *derived。 (请参见下面的示例。)
-
指针之间的距离 (以字节为单位) 必须是
T
大小的精确倍数。 -
指针之间的距离 (以字节为单位) 不会溢出
isize
。 -
该距离不能依赖于 “wrapping around” 地址空间。
Rust 类型从不大于 isize::MAX
,并且 Rust 分配从不环绕地址空间,因此,任何 Rust 类型 T
的某个值内的两个指针将始终满足最后两个条件。
标准库通常还确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不超过 isize::MAX
字节,因此 ptr_into_vec.offset_from(vec.as_ptr())
始终满足最后两个条件。
从根本上说,大多数平台甚至都无法构建如此大的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
(请注意,offset
和 add
也具有类似的限制,因此也不能在如此大的分配上使用。)
Panics
如果 T
是零大小类型 (“ZST”),则此函数 panics。
Examples
基本用法:
let a = [0; 5];
let ptr1: *const i32 = &a[1];
let ptr2: *const i32 = &a[3];
unsafe {
assert_eq!(ptr2.offset_from(ptr1), 2);
assert_eq!(ptr1.offset_from(ptr2), -2);
assert_eq!(ptr1.offset(2), ptr2);
assert_eq!(ptr2.offset(-2), ptr1);
}
Run不正确 用法:
let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8;
let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8;
let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
// 将 ptr2_other 设置为 ptr2 的 "alias",但从 ptr1 派生。
let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff);
assert_eq!(ptr2 as usize, ptr2_other as usize);
// 由于 ptr2_other 和 ptr2 是从指向不同对象的指针派生的,因此即使它们指向相同的地址,计算其偏移量也是未定义的行为!
unsafe {
let zero = ptr2_other.offset_from(ptr2); // 未定义的行为
}
Runconst: unstable · sourcepub unsafe fn byte_offset_from<U>(self, origin: *const U) -> isizewhere
U: ?Sized,
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_offset_from<U>(self, origin: *const U) -> isizewhere U: ?Sized,
pointer_byte_offsets
#96283)计算两个指针之间的距离。返回值以 字节 为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 offset_from。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅考虑数据指针,忽略元数据。
const: unstable · sourcepub unsafe fn sub_ptr(self, origin: *const T) -> usize
🔬This is a nightly-only experimental API. (ptr_sub_ptr
#95892)
pub unsafe fn sub_ptr(self, origin: *const T) -> usize
ptr_sub_ptr
#95892)计算两个指针之间的距离,where 已知 self
等于或大于 origin
。返回值以 T 为单位: 以字节为单位的距离除以 mem::size_of::<T>()
。
这将计算 offset_from
将计算的相同值,但附加的前提条件是偏移量保证为非 negative。
此方法等同于 usize::try_from(self.offset_from(origin)).unwrap_unchecked()
,但它为优化器提供了更多的信息,这有时可以使其在某些后端优化得更好。
这个方法可以看作是恢复传递给 add
的 count
(或者,使用其他顺序的参数,到 sub
).
以下都是等价的,假设它们的安全先决条件得到满足:
ptr.sub_ptr(origin) == count
origin.add(count) == ptr
ptr.sub(count) == origin
RunSafety
-
指针之间的距离必须是非 negative (
self >= origin
) -
所有
offset_from
的安全条件也适用于此方法; 查看完整的详细信息。
重要的是,尽管此方法的返回类型能够表示更大的偏移量,但仍然不允许传递相差超过 isize::MAX
bytes 的指针。
因此,此方法的结果将始终小于或等于 isize::MAX as usize
。
Panics
如果 T
是零大小类型 (“ZST”),则此函数 panics。
Examples
#![feature(ptr_sub_ptr)]
let a = [0; 5];
let ptr1: *const i32 = &a[1];
let ptr2: *const i32 = &a[3];
unsafe {
assert_eq!(ptr2.sub_ptr(ptr1), 2);
assert_eq!(ptr1.add(2), ptr2);
assert_eq!(ptr2.sub(2), ptr1);
assert_eq!(ptr2.sub_ptr(ptr2), 0);
}
// 这是不正确的,因为指针的顺序不正确:
// ptr1.sub_ptr(ptr2)
Runconst: unstable · sourcepub fn guaranteed_eq(self, other: *const T) -> Option<bool>
🔬This is a nightly-only experimental API. (const_raw_ptr_comparison
#53020)
pub fn guaranteed_eq(self, other: *const T) -> Option<bool>
const_raw_ptr_comparison
#53020)返回两个指针是否保证相等。
在运行时,这个函数的行为类似于 Some(self == other)
。
但是,在某些情况下 (例如,编译时评估),并不总是可以确定两个指针的相等性,因此该函数可能会虚假地返回 None
以获取稍后实际上证明其相等性已知的指针。
但是当它返回 Some
时,可以保证知道指针的相等性。
返回值可能会从 Some
更改为 None
,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。
建议仅将此函数用于性能优化,其中此函数的虚假 None
返回值不会影响结果,而只会影响性能。
尚未探讨使用此方法使运行时和编译时代码表现不同的后果。
不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。
const: unstable · sourcepub fn guaranteed_ne(self, other: *const T) -> Option<bool>
🔬This is a nightly-only experimental API. (const_raw_ptr_comparison
#53020)
pub fn guaranteed_ne(self, other: *const T) -> Option<bool>
const_raw_ptr_comparison
#53020)返回是否保证两个指针不相等。
在运行时,这个函数的行为类似于 Some(self != other)
。
然而,在某些情况下 (例如,编译时求值),并不总是可以确定两个指针的不等式,因此该函数可能会虚假地返回 None
以获取后来实际证明其不等式的指针。
但是当它返回 Some
时,指针的不等式保证是已知的。
返回值可能会从 Some
更改为 None
,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。
建议仅将此函数用于性能优化,其中此函数的虚假 None
返回值不会影响结果,而只会影响性能。
尚未探讨使用此方法使运行时和编译时代码表现不同的后果。
不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。
1.26.0 (const: 1.61.0) · sourcepub const unsafe fn add(self, count: usize) -> *const T
pub const unsafe fn add(self, count: usize) -> *const T
计算与指针的偏移量 (.offset(count as isize)
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合
usize
。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_add
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
let s: &str = "123";
let ptr: *const u8 = s.as_ptr();
unsafe {
println!("{}", *ptr.add(1) as char);
println!("{}", *ptr.add(2) as char);
}
Runconst: unstable · sourcepub unsafe fn byte_add(self, count: usize) -> *const T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_add(self, count: usize) -> *const T
pointer_byte_offsets
#96283)以字节为单位计算指针的偏移量 (方便 .byte_offset(count as isize)
)。
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 add。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.61.0) · sourcepub const unsafe fn sub(self, count: usize) -> *const T
pub const unsafe fn sub(self, count: usize) -> *const T
计算与指针的偏移量 (.offset((count as isize).wrapping_neg())
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量不能超过
isize::MAX
个 字节。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合使用大小。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len()).sub(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_sub
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
let s: &str = "123";
unsafe {
let end: *const u8 = s.as_ptr().add(3);
println!("{}", *end.sub(1) as char);
println!("{}", *end.sub(2) as char);
}
Runconst: unstable · sourcepub unsafe fn byte_sub(self, count: usize) -> *const T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_sub(self, count: usize) -> *const T
pointer_byte_offsets
#96283)以字节为单位计算指针的偏移量 (方便 .byte_offset((count as isize).wrapping_neg())
)。
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 sub。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.61.0) · sourcepub const fn wrapping_add(self, count: usize) -> *const T
pub const fn wrapping_add(self, count: usize) -> *const T
使用换行算法计算与指针的偏移量。
(为 .wrapping_offset(count as isize)
带来的便利)
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
此操作本身始终是安全的,但使用结果指针则不安全。
结果指针 “remembers” 是 self
指向的 分配对象; 它不得用于读取或写入其他分配的对象。
换句话说,即使我们假设 T
的大小为 1
并且没有溢出,let z = x.wrapping_add((y as usize) - (x as usize))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 add
相比,此方法从根本上延迟了留在同一分配对象内的需求: add
是跨越对象边界时的立即未定义行为; wrapping_add
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
add
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
// 使用裸指针以两个元素为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_add(6);
// 此循环打印 "1, 3, 5, "
while ptr != end_rounded_up {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_add(step);
}
Runconst: unstable · sourcepub fn wrapping_byte_add(self, count: usize) -> *const T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub fn wrapping_byte_add(self, count: usize) -> *const T
pointer_byte_offsets
#96283)使用环绕算法计算与指针的偏移量 (以字节为单位)。
(便于 .wrapping_byte_offset(计为 isize)
)
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 wrapping_add。
请参见该方法以获取文档。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.61.0) · sourcepub const fn wrapping_sub(self, count: usize) -> *const T
pub const fn wrapping_sub(self, count: usize) -> *const T
使用换行算法计算与指针的偏移量。
(为 .wrapping_offset((count as isize).wrapping_neg())
带来的便利)
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
此操作本身始终是安全的,但使用结果指针则不安全。
结果指针 “remembers” 是 self
指向的 分配对象; 它不得用于读取或写入其他分配的对象。
换句话说,即使我们假设 T
的大小为 1
并且没有溢出,let z = x.wrapping_sub((x as usize) - (y as usize))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 sub
相比,此方法从根本上延迟了留在同一分配对象内的需求: sub
是跨越对象边界时的立即未定义行为; wrapping_sub
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
sub
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
// 使用裸指针以两个元素 (backwards) 为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let start_rounded_down = ptr.wrapping_sub(2);
ptr = ptr.wrapping_add(4);
let step = 2;
// 此循环打印 "5, 3, 1, "
while ptr != start_rounded_down {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_sub(step);
}
Runconst: unstable · sourcepub fn wrapping_byte_sub(self, count: usize) -> *const T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub fn wrapping_byte_sub(self, count: usize) -> *const T
pointer_byte_offsets
#96283)使用环绕算法计算与指针的偏移量 (以字节为单位)。
(为 .wrapping_offset((count as isize).wrapping_neg())
带来的便利)
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 wrapping_sub。
请参见该方法以获取文档。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.71.0) · sourcepub const unsafe fn read(self) -> T
pub const unsafe fn read(self) -> T
从 self
读取值而不移动它。
这将使 self
中的内存保持不变。
有关安全性问题和示例,请参见 ptr::read
。
1.26.0 · sourcepub unsafe fn read_volatile(self) -> T
pub unsafe fn read_volatile(self) -> T
对 self
的值进行易失性读取,而无需移动它。这将使 self
中的内存保持不变。
易失性操作旨在作用于 I/O 存储器,并保证编译器不会在其他易失性操作中对易失性操作进行清除或重新排序。
有关安全性问题和示例,请参见 ptr::read_volatile
。
1.26.0 (const: 1.71.0) · sourcepub const unsafe fn read_unaligned(self) -> T
pub const unsafe fn read_unaligned(self) -> T
1.26.0 (const: 1.63.0) · sourcepub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
将 count * size_of<T>
字节从 self
复制到 dest
。
源和目标可能 不 重叠。
NOTE: 这与 ptr::copy_nonoverlapping
具有相同的参数顺序。
有关安全性问题和示例,请参见 ptr::copy_nonoverlapping
。
1.36.0 (const: unstable) · sourcepub fn align_offset(self, align: usize) -> usize
pub fn align_offset(self, align: usize) -> usize
计算为使其与 align
对齐而需要应用到指针的偏移量。
如果无法对齐指针,则实现将返回 usize::MAX
。
允许实现 始终 返回 usize::MAX
。
只有算法的性能可以取决于此处是否可获得可用的偏移量,而不取决于其正确性。
偏移量以 T
元素的数量表示,而不是以字节表示。返回的值可以与 wrapping_add
方法一起使用。
不能保证偏移指针不会溢出或超出指针所指向的分配范围。
调用者应确保返回的偏移量在对齐方式以外的所有方面都是正确的。
Panics
如果 align
不是 2 的幂,则函数 panics。
Examples
将相邻的 u8
作为 u16
进行访问
use std::mem::align_of;
let x = [5_u8, 6, 7, 8, 9];
let ptr = x.as_ptr();
let offset = ptr.align_offset(align_of::<u16>());
if offset < x.len() - 1 {
let u16_ptr = ptr.add(offset).cast::<u16>();
assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7]));
} else {
// 虽然指针可以通过 `offset` 对齐,但它会指向分配之外
}
Runconst: unstable · sourcepub fn is_aligned(self) -> bool
🔬This is a nightly-only experimental API. (pointer_is_aligned
#96284)
pub fn is_aligned(self) -> bool
pointer_is_aligned
#96284)返回指针是否为 T
正确对齐。
Examples
#![feature(pointer_is_aligned)]
#![feature(pointer_byte_offsets)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
let data = AlignedI32(42);
let ptr = &data as *const AlignedI32;
assert!(ptr.is_aligned());
assert!(!ptr.wrapping_byte_add(1).is_aligned());
Run在编译时
Note: 编译时的对齐是实验性的,可能会发生变化。有关详细信息,请参见 tracking issue。
在编译时,编译器可能不知道值将在内存中的何处结束。
在编译时对从引用创建的指针调用此函数将仅在保证指针对齐的情况下返回 true
。
这意味着如果将指针转换为比引用的底层分配具有更严格对齐的类型,则指针永远不会对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,图元的对齐方式小于它们的大小。
#[repr(align(4))]
struct AlignedI32(i32);
#[repr(align(8))]
struct AlignedI64(i64);
const _: () = {
let data = AlignedI32(42);
let ptr = &data as *const AlignedI32;
assert!(ptr.is_aligned());
// 在运行时 `ptr1` 或 `ptr2` 将对齐,但在编译时两者都不对齐。
let ptr1 = ptr.cast::<AlignedI64>();
let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
assert!(!ptr1.is_aligned());
assert!(!ptr2.is_aligned());
};
Run由于此行为,即使编译时指针未对齐,派生自编译时指针的运行时指针也可能对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,图元的对齐方式小于它们的大小。
#[repr(align(4))]
struct AlignedI32(i32);
#[repr(align(8))]
struct AlignedI64(i64);
// 在编译时,`COMPTIME_PTR` 和 `COMPTIME_PTR + 1` 都没有对齐。
const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
// 在运行时,`runtime_ptr` 或 `runtime_ptr + 1` 对齐。
let runtime_ptr = COMPTIME_PTR;
assert_ne!(
runtime_ptr.cast::<AlignedI64>().is_aligned(),
runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
);
Run如果指针是从固定地址创建的,则此函数在运行时和编译时的行为相同。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,图元的对齐方式小于它们的大小。
#[repr(align(4))]
struct AlignedI32(i32);
#[repr(align(8))]
struct AlignedI64(i64);
const _: () = {
let ptr = 40 as *const AlignedI32;
assert!(ptr.is_aligned());
// 对于具有已知地址的指针,运行时和编译时行为是相同的。
let ptr1 = ptr.cast::<AlignedI64>();
let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
assert!(ptr1.is_aligned());
assert!(!ptr2.is_aligned());
};
Runconst: unstable · sourcepub fn is_aligned_to(self, align: usize) -> bool
🔬This is a nightly-only experimental API. (pointer_is_aligned
#96284)
pub fn is_aligned_to(self, align: usize) -> bool
pointer_is_aligned
#96284)返回指针是否与 align
对齐。
对于非 Sized
指针,此操作仅考虑数据指针,而忽略元数据。
Panics
如果 align
不是 2 的幂 (包括 0),函数会出现 panic。
Examples
#![feature(pointer_is_aligned)]
#![feature(pointer_byte_offsets)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
let data = AlignedI32(42);
let ptr = &data as *const AlignedI32;
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
Run在编译时
Note: 编译时的对齐是实验性的,可能会发生变化。有关详细信息,请参见 tracking issue。
在编译时,编译器可能不知道值将在内存中的何处结束。
在编译时对从引用创建的指针调用此函数将仅在保证指针对齐的情况下返回 true
。
这意味着指针不能比引用的底层分配更严格地对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
const _: () = {
let data = AlignedI32(42);
let ptr = &data as *const AlignedI32;
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
// 在编译时,我们确定指针没有对齐到 8.
assert!(!ptr.is_aligned_to(8));
assert!(!ptr.wrapping_add(1).is_aligned_to(8));
};
Run由于此行为,即使编译时指针未对齐,派生自编译时指针的运行时指针也可能对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
// 在编译时,`COMPTIME_PTR` 和 `COMPTIME_PTR + 1` 都没有对齐。
const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
// 在运行时,`runtime_ptr` 或 `runtime_ptr + 1` 对齐。
let runtime_ptr = COMPTIME_PTR;
assert_ne!(
runtime_ptr.is_aligned_to(8),
runtime_ptr.wrapping_add(1).is_aligned_to(8),
);
Run如果指针是从固定地址创建的,则此函数在运行时和编译时的行为相同。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
const _: () = {
let ptr = 40 as *const u8;
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
assert!(ptr.is_aligned_to(8));
assert!(!ptr.is_aligned_to(16));
};
Runsource§impl<T> *mut Twhere
T: ?Sized,
impl<T> *mut Twhere T: ?Sized,
const: unstable · sourcepub fn is_null(self) -> bool
pub fn is_null(self) -> bool
如果指针为空,则返回 true
。
请注意,未定义大小的类型具有许多可能的空指针,因为仅考虑原始数据指针,而不考虑其长度,vtable 等。 因此,两个为空的指针可能仍不能相互比较相等。
常量评估期间的行为
在 const 评估期间使用此函数时,对于在运行时结果为空的指针,它可能返回 false
。
具体来说,当指向某个内存的指针超出其范围的偏移量 (使结果指针为空) 时,函数仍将返回 false
。
CTFE 无法知道该内存的绝对位置,因此我们无法确定指针是否为空。
Examples
let mut s = [1, 2, 3];
let ptr: *mut u32 = s.as_mut_ptr();
assert!(!ptr.is_null());
Runconst: unstable · sourcepub fn with_metadata_of<U>(self, meta: *const U) -> *mut Uwhere
U: ?Sized,
🔬This is a nightly-only experimental API. (set_ptr_value
#75091)
pub fn with_metadata_of<U>(self, meta: *const U) -> *mut Uwhere U: ?Sized,
set_ptr_value
#75091)在另一种类型的新指针中使用指针值。
如果 meta
是指向未定义大小类型的 (fat) 指针,此操作将忽略指针部分,而对于指向大小类型的 (thin) 指针,这与简单强制转换具有相同的效果。
生成的指针将具有 self
的来源,即,对于胖指针,此操作在语义上与创建数据指针值为 self
但元数据为 meta
的新胖指针相同。
Examples
此函数主要用于允许对潜在的胖指针进行按字节指针算术运算:
#![feature(set_ptr_value)]
let mut arr: [i32; 3] = [1, 2, 3];
let mut ptr = arr.as_mut_ptr() as *mut dyn Debug;
let thin = ptr as *mut u8;
unsafe {
ptr = thin.add(8).with_metadata_of(ptr);
println!("{:?}", &*ptr); // 将打印 "3"
}
Run1.65.0 (const: 1.65.0) · sourcepub const fn cast_const(self) -> *const T
pub const fn cast_const(self) -> *const T
更改常量而不更改类型。
这比 as
安全一点,因为如果重构代码,它不会默默地改变类型。
虽然不是严格要求 (*mut T
强制转换为 *const T
),但这是为了与 *const T
上的 cast_mut
对称而提供的,如果使用它来代替隐式强制,则可能具有文档值。
sourcepub fn to_bits(self) -> usize
👎Deprecated since 1.67.0: replaced by the expose_addr
method, or update your code to follow the strict provenance rules using its APIs🔬This is a nightly-only experimental API. (ptr_to_from_bits
#91126)
pub fn to_bits(self) -> usize
expose_addr
method, or update your code to follow the strict provenance rules using its APIsptr_to_from_bits
#91126)将指针强制转换为原始位。
这等效于 as usize
,但更具体以增强可读性。
相反的方法是 from_bits
。
特别是,*p as usize
和 p as usize
都会编译指向数字类型的指针,但做的事情却截然不同,因此使用它有助于强调读取位是有意的。
Examples
#![feature(ptr_to_from_bits)]
let mut array = [13, 42];
let mut it = array.iter_mut();
let p0: *mut i32 = it.next().unwrap();
assert_eq!(<*mut _>::from_bits(p0.to_bits()), p0);
let p1: *mut i32 = it.next().unwrap();
assert_eq!(p1.to_bits() - p0.to_bits(), 4);
}
Runsourcepub fn from_bits(bits: usize) -> *mut T
👎Deprecated since 1.67.0: replaced by the ptr::from_exposed_addr_mut
function, or update your code to follow the strict provenance rules using its APIs🔬This is a nightly-only experimental API. (ptr_to_from_bits
#91126)
pub fn from_bits(bits: usize) -> *mut T
ptr::from_exposed_addr_mut
function, or update your code to follow the strict provenance rules using its APIsptr_to_from_bits
#91126)sourcepub fn addr(self) -> usize
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn addr(self) -> usize
strict_provenance
#95228)获取指针的 “address” 部分。
这类似于 self as usize
,它在语义上丢弃了provenance 和address-space 信息。
但是,与 self as usize
不同,将返回的地址转换回指针会产生 invalid
,这对于解引用来说是未定义的行为。
要正确恢复丢失的信息并获得可解引用的指针,请使用 with_addr
或 map_addr
。
如果由于无法保留具有所需出处的指针而无法使用这些 API,请改用 expose_addr
和 from_exposed_addr_mut
。
但是,请注意,这会降低您的代码的可移植性,并且不太适合用于检查是否符合 Rust 内存模型的工具。
在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。 需要在指针中存储附加信息的平台可以执行表示的改变,以产生仅包含指针的地址部分的值。 这意味着什么取决于平台来定义。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,因此可能会在 future 中发生变化 (包括可能削弱这一点,使其完全等同于 self as usize
)。
有关详细信息,请参见 [模块文档。
sourcepub fn expose_addr(self) -> usize
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn expose_addr(self) -> usize
strict_provenance
#95228)获取指针的 “address” 部分,并暴露 “provenance” 部分,以便将来在 from_exposed_addr
中使用。
这相当于 self as usize
,它在语义上丢弃了 provenance 和 address-space 信息。
此外,这 (如 as
演员表) 具有将出处标记为 ‘exposed’ 的隐式副作用,因此在支持它的平台上,您可以稍后调用 from_exposed_addr_mut
来重构原始指针,包括其出处。
(如果需要,重建地址空间信息是您的责任。)
使用这种方法意味着代码没有遵循严格的出处规则。
支持 from_exposed_addr_mut
会使规范和推理复杂化,并且可能不受帮助您与 Rust 内存模型保持一致的工具的支持,因此建议尽可能使用 addr
。
在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。
需要在指针中存储附加信息的平台可能不支持此操作,因为 from_exposed_addr_mut
工作所需的 ‘expose’ 副作用通常不可用。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档。
sourcepub fn with_addr(self, addr: usize) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn with_addr(self, addr: usize) -> *mut T
strict_provenance
#95228)使用给定地址创建一个新指针。
这执行与 addr as ptr
强制转换相同的操作,但将 self
的 address-space 和 provenance 复制到新指针。
这使我们能够动态地保存和传播这些重要信息,而这在其他情况下使用一元强制转换是不可能的。
这相当于使用 wrapping_offset
将 self
偏移到给定地址,因此具有所有相同的功能和限制。
此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档。
sourcepub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> *mut T
🔬This is a nightly-only experimental API. (strict_provenance
#95228)
pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> *mut T
strict_provenance
#95228)const: unstable · sourcepub fn to_raw_parts(self) -> (*mut (), <T as Pointee>::Metadata)
🔬This is a nightly-only experimental API. (ptr_metadata
#81513)
pub fn to_raw_parts(self) -> (*mut (), <T as Pointee>::Metadata)
ptr_metadata
#81513)将指针 (可能是宽指针) 分解为其地址和元数据组件。
以后可以使用 from_raw_parts_mut
重建指针。
1.9.0 (const: unstable) · sourcepub unsafe fn as_ref<'a>(self) -> Option<&'a T>
pub unsafe fn as_ref<'a>(self) -> Option<&'a T>
如果指针为空,则返回 None
,否则返回 Some
中包装的值的共享引用。如果该值可能未初始化,则必须改用 as_uninit_ref
。
对于可变的对应物,请参见 as_mut
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
指针必须指向
T
的初始化实例。 -
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能发生可变 (UnsafeCell
内部除外)。
即使未使用此方法的结果也是如此! (关于初始化的部分尚未完全决定,但是直到确定之前,唯一安全的方法是确保它们确实被初始化。)
Examples
let ptr: *mut u8 = &mut 10u8 as *mut u8;
unsafe {
if let Some(val_back) = ptr.as_ref() {
println!("We got back the value: {val_back}!");
}
}
Run空未经检查的版本
如果确定指针永远不会为空,并且正在寻找某种返回 &T
而不是 Option<&T>
的 as_ref_unchecked
,请知道您可以直接引用该指针。
let ptr: *mut u8 = &mut 10u8 as *mut u8;
unsafe {
let val_back = &*ptr;
println!("We got back the value: {val_back}!");
}
Runconst: unstable · sourcepub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
🔬This is a nightly-only experimental API. (ptr_as_uninit
#75402)
pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
ptr_as_uninit
#75402)如果指针为空,则返回 None
,否则返回 Some
中包装的值的共享引用。
与 as_ref
相比,这不需要将该值初始化。
对于可变的对应物,请参见 as_uninit_mut
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。特别是,当这个引用存在时,指针指向的内存不能发生可变 (
UnsafeCell
内部除外)。
即使未使用此方法的结果也是如此!
Examples
#![feature(ptr_as_uninit)]
let ptr: *mut u8 = &mut 10u8 as *mut u8;
unsafe {
if let Some(val_back) = ptr.as_uninit_ref() {
println!("We got back the value: {}!", val_back.assume_init());
}
}
Runconst: 1.61.0 · sourcepub const unsafe fn offset(self, count: isize) -> *mut T
pub const unsafe fn offset(self, count: isize) -> *mut T
计算与指针的偏移量。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度总和 (以字节为单位) 必须适合于 usize。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_offset
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
let mut s = [1, 2, 3];
let ptr: *mut u32 = s.as_mut_ptr();
unsafe {
println!("{}", *ptr.offset(1));
println!("{}", *ptr.offset(2));
}
Runconst: unstable · sourcepub unsafe fn byte_offset(self, count: isize) -> *mut T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_offset(self, count: isize) -> *mut T
pointer_byte_offsets
#96283)计算与指针的偏移量 (以字节为单位)。
count
以 字节 为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 offset。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.16.0 (const: 1.61.0) · sourcepub const fn wrapping_offset(self, count: isize) -> *mut T
pub const fn wrapping_offset(self, count: isize) -> *mut T
使用换行算法计算与指针的偏移量。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
此操作本身始终是安全的,但使用结果指针则不安全。
结果指针 “remembers” 是 self
指向的 分配对象; 它不得用于读取或写入其他分配的对象。
换句话说,即使我们假设 T
的大小为 1
并且没有溢出,let z = x.wrapping_offset((y as isize) - (x as isize))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 offset
相比,此方法从根本上延迟了留在同一分配对象内的需求: offset
是跨越对象边界时的立即未定义行为; wrapping_offset
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
offset
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
// 使用裸指针以两个元素为增量进行迭代
let mut data = [1u8, 2, 3, 4, 5];
let mut ptr: *mut u8 = data.as_mut_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_offset(6);
while ptr != end_rounded_up {
unsafe {
*ptr = 0;
}
ptr = ptr.wrapping_offset(step);
}
assert_eq!(&data, &[0, 2, 0, 4, 0]);
Runconst: unstable · sourcepub fn wrapping_byte_offset(self, count: isize) -> *mut T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub fn wrapping_byte_offset(self, count: isize) -> *mut T
pointer_byte_offsets
#96283)使用环绕算法计算与指针的偏移量 (以字节为单位)。
count
以 字节 为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 wrapping_offset。
请参见该方法以获取文档。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
sourcepub fn mask(self, mask: usize) -> *mut T
🔬This is a nightly-only experimental API. (ptr_mask
#98290)
pub fn mask(self, mask: usize) -> *mut T
ptr_mask
#98290)根据掩码屏蔽指针的位。
这对 ptr.map_addr(|a| a & mask)
来说很方便。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
Examples
#![feature(ptr_mask, strict_provenance)]
let mut v = 17_u32;
let ptr: *mut u32 = &mut v;
// `u32` 是 4 字节对齐的,这意味着低 2 位总是 0.
let tag_mask = 0b11;
let ptr_mask = !tag_mask;
// 我们可以在这些低位存储一些东西
let tagged_ptr = ptr.map_addr(|a| a | 0b10);
// 取回 "tag"
let tag = tagged_ptr.addr() & tag_mask;
assert_eq!(tag, 0b10);
// 注意 `tagged_ptr` 是未对齐的,它是 UB 读取 from/write 到它。
// 要获得原始指针 `mask` 可以使用:
let masked_ptr = tagged_ptr.mask(ptr_mask);
assert_eq!(unsafe { *masked_ptr }, 17);
unsafe { *masked_ptr = 0 };
assert_eq!(v, 0);
Run1.9.0 (const: unstable) · sourcepub unsafe fn as_mut<'a>(self) -> Option<&'a mut T>
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T>
如果指针为 null,则返回 None
,否则返回 Some
中包装的值的唯一引用。如果该值可能未初始化,则必须改用 as_uninit_mut
。
有关共享副本,请参见 as_ref
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
指针必须指向
T
的初始化实例。 -
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能通过任何其他指针访问 (读取或写入)。
即使未使用此方法的结果也是如此! (关于初始化的部分尚未完全决定,但是直到确定之前,唯一安全的方法是确保它们确实被初始化。)
Examples
let mut s = [1, 2, 3];
let ptr: *mut u32 = s.as_mut_ptr();
let first_value = unsafe { ptr.as_mut().unwrap() };
*first_value = 4;
println!("{s:?}"); // 它会打印: "[4, 2, 3]"。
Run空未经检查的版本
如果确定指针永远不会为空,并且正在寻找某种返回 &mut T
而不是 Option<&mut T>
的 as_mut_unchecked
,请知道您可以直接引用该指针。
let mut s = [1, 2, 3];
let ptr: *mut u32 = s.as_mut_ptr();
let first_value = unsafe { &mut *ptr };
*first_value = 4;
println!("{s:?}"); // 它会打印: "[4, 2, 3]"。
Runconst: unstable · sourcepub unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit<T>>
🔬This is a nightly-only experimental API. (ptr_as_uninit
#75402)
pub unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit<T>>
ptr_as_uninit
#75402)如果指针为 null,则返回 None
,否则返回 Some
中包装的值的唯一引用。
与 as_mut
相比,这不需要将该值初始化。
有关共享副本,请参见 as_uninit_ref
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。特别是,当这个引用存在时,指针指向的内存不能通过任何其他指针访问 (读取或写入)。
即使未使用此方法的结果也是如此!
const: unstable · sourcepub fn guaranteed_eq(self, other: *mut T) -> Option<bool>
🔬This is a nightly-only experimental API. (const_raw_ptr_comparison
#53020)
pub fn guaranteed_eq(self, other: *mut T) -> Option<bool>
const_raw_ptr_comparison
#53020)返回两个指针是否保证相等。
在运行时,这个函数的行为类似于 Some(self == other)
。
但是,在某些情况下 (例如,编译时评估),并不总是可以确定两个指针的相等性,因此该函数可能会虚假地返回 None
以获取稍后实际上证明其相等性已知的指针。
但是当它返回 Some
时,可以保证知道指针的相等性。
返回值可能会从 Some
更改为 None
,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。
建议仅将此函数用于性能优化,其中此函数的虚假 None
返回值不会影响结果,而只会影响性能。
尚未探讨使用此方法使运行时和编译时代码表现不同的后果。
不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。
const: unstable · sourcepub fn guaranteed_ne(self, other: *mut T) -> Option<bool>
🔬This is a nightly-only experimental API. (const_raw_ptr_comparison
#53020)
pub fn guaranteed_ne(self, other: *mut T) -> Option<bool>
const_raw_ptr_comparison
#53020)返回是否保证两个指针不相等。
在运行时,这个函数的行为类似于 Some(self != other)
。
然而,在某些情况下 (例如,编译时求值),并不总是可以确定两个指针的不等式,因此该函数可能会虚假地返回 None
以获取后来实际证明其不等式的指针。
但是当它返回 Some
时,指针的不等式保证是已知的。
返回值可能会从 Some
更改为 None
,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。
建议仅将此函数用于性能优化,其中此函数的虚假 None
返回值不会影响结果,而只会影响性能。
尚未探讨使用此方法使运行时和编译时代码表现不同的后果。
不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。
1.47.0 (const: 1.65.0) · sourcepub const unsafe fn offset_from(self, origin: *const T) -> isize
pub const unsafe fn offset_from(self, origin: *const T) -> isize
计算两个指针之间的距离。返回值以 T 为单位: 以字节为单位的距离除以 mem::size_of::<T>()
。
该函数是 offset
的逆函数。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和其他指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
两个指针必须是指向同一对象的指针的 *derived。 (请参见下面的示例。)
-
指针之间的距离 (以字节为单位) 必须是
T
大小的精确倍数。 -
指针之间的距离 (以字节为单位) 不会溢出
isize
。 -
该距离不能依赖于 “wrapping around” 地址空间。
Rust 类型从不大于 isize::MAX
,并且 Rust 分配从不环绕地址空间,因此,任何 Rust 类型 T
的某个值内的两个指针将始终满足最后两个条件。
标准库通常还确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不超过 isize::MAX
字节,因此 ptr_into_vec.offset_from(vec.as_ptr())
始终满足最后两个条件。
从根本上说,大多数平台甚至都无法构建如此大的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
(请注意,offset
和 add
也具有类似的限制,因此也不能在如此大的分配上使用。)
Panics
如果 T
是零大小类型 (“ZST”),则此函数 panics。
Examples
基本用法:
let mut a = [0; 5];
let ptr1: *mut i32 = &mut a[1];
let ptr2: *mut i32 = &mut a[3];
unsafe {
assert_eq!(ptr2.offset_from(ptr1), 2);
assert_eq!(ptr1.offset_from(ptr2), -2);
assert_eq!(ptr1.offset(2), ptr2);
assert_eq!(ptr2.offset(-2), ptr1);
}
Run不正确 用法:
let ptr1 = Box::into_raw(Box::new(0u8));
let ptr2 = Box::into_raw(Box::new(1u8));
let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
// 将 ptr2_other 设置为 ptr2 的 "alias",但从 ptr1 派生。
let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff);
assert_eq!(ptr2 as usize, ptr2_other as usize);
// 由于 ptr2_other 和 ptr2 是从指向不同对象的指针派生的,因此即使它们指向相同的地址,计算其偏移量也是未定义的行为!
unsafe {
let zero = ptr2_other.offset_from(ptr2); // 未定义的行为
}
Runconst: unstable · sourcepub unsafe fn byte_offset_from<U>(self, origin: *const U) -> isizewhere
U: ?Sized,
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_offset_from<U>(self, origin: *const U) -> isizewhere U: ?Sized,
pointer_byte_offsets
#96283)计算两个指针之间的距离。返回值以 字节 为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 offset_from。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅考虑数据指针,忽略元数据。
const: unstable · sourcepub unsafe fn sub_ptr(self, origin: *const T) -> usize
🔬This is a nightly-only experimental API. (ptr_sub_ptr
#95892)
pub unsafe fn sub_ptr(self, origin: *const T) -> usize
ptr_sub_ptr
#95892)计算两个指针之间的距离,where 已知 self
等于或大于 origin
。返回值以 T 为单位: 以字节为单位的距离除以 mem::size_of::<T>()
。
这将计算 offset_from
将计算的相同值,但附加的前提条件是偏移量保证为非 negative。
此方法等同于 usize::try_from(self.offset_from(origin)).unwrap_unchecked()
,但它为优化器提供了更多的信息,这有时可以使其在某些后端优化得更好。
这个方法可以看作是恢复传递给 add
的 count
(或者,使用其他顺序的参数,到 sub
).
以下都是等价的,假设它们的安全先决条件得到满足:
ptr.sub_ptr(origin) == count
origin.add(count) == ptr
ptr.sub(count) == origin
RunSafety
-
指针之间的距离必须是非 negative (
self >= origin
) -
所有
offset_from
的安全条件也适用于此方法; 查看完整的详细信息。
重要的是,尽管此方法的返回类型能够表示更大的偏移量,但仍然不允许传递相差超过 isize::MAX
bytes 的指针。
因此,此方法的结果将始终小于或等于 isize::MAX as usize
。
Panics
如果 T
是零大小类型 (“ZST”),则此函数 panics。
Examples
#![feature(ptr_sub_ptr)]
let mut a = [0; 5];
let p: *mut i32 = a.as_mut_ptr();
unsafe { let ptr1: *mut i32 = p.add(1);
let ptr2: *mut i32 = p.add(3);
assert_eq!(ptr2.sub_ptr(ptr1), 2);
assert_eq!(ptr1.add(2), ptr2);
assert_eq!(ptr2.sub(2), ptr1);
assert_eq!(ptr2.sub_ptr(ptr2), 0);
}
// 这是不正确的,因为指针的顺序不正确:
// ptr1.offset_from(ptr2)
Run1.26.0 (const: 1.61.0) · sourcepub const unsafe fn add(self, count: usize) -> *mut T
pub const unsafe fn add(self, count: usize) -> *mut T
计算与指针的偏移量 (.offset(count as isize)
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合
usize
。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_add
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
let s: &str = "123";
let ptr: *const u8 = s.as_ptr();
unsafe {
println!("{}", *ptr.add(1) as char);
println!("{}", *ptr.add(2) as char);
}
Runconst: unstable · sourcepub unsafe fn byte_add(self, count: usize) -> *mut T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_add(self, count: usize) -> *mut T
pointer_byte_offsets
#96283)以字节为单位计算指针的偏移量 (方便 .byte_offset(count as isize)
)。
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 add。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.61.0) · sourcepub const unsafe fn sub(self, count: usize) -> *mut T
pub const unsafe fn sub(self, count: usize) -> *mut T
计算与指针的偏移量 (.offset((count as isize).wrapping_neg())
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量不能超过
isize::MAX
个 字节。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合使用大小。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len()).sub(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_sub
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
let s: &str = "123";
unsafe {
let end: *const u8 = s.as_ptr().add(3);
println!("{}", *end.sub(1) as char);
println!("{}", *end.sub(2) as char);
}
Runconst: unstable · sourcepub unsafe fn byte_sub(self, count: usize) -> *mut T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub unsafe fn byte_sub(self, count: usize) -> *mut T
pointer_byte_offsets
#96283)以字节为单位计算指针的偏移量 (方便 .byte_offset((count as isize).wrapping_neg())
)。
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 sub。
有关文档和安全要求,请参见该方法。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.61.0) · sourcepub const fn wrapping_add(self, count: usize) -> *mut T
pub const fn wrapping_add(self, count: usize) -> *mut T
使用换行算法计算与指针的偏移量。
(为 .wrapping_offset(count as isize)
带来的便利)
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
此操作本身始终是安全的,但使用结果指针则不安全。
结果指针 “remembers” 是 self
指向的 分配对象; 它不得用于读取或写入其他分配的对象。
换句话说,即使我们假设 T
的大小为 1
并且没有溢出,let z = x.wrapping_add((y as usize) - (x as usize))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 add
相比,此方法从根本上延迟了留在同一分配对象内的需求: add
是跨越对象边界时的立即未定义行为; wrapping_add
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
add
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
// 使用裸指针以两个元素为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_add(6);
// 此循环打印 "1, 3, 5, "
while ptr != end_rounded_up {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_add(step);
}
Runconst: unstable · sourcepub fn wrapping_byte_add(self, count: usize) -> *mut T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub fn wrapping_byte_add(self, count: usize) -> *mut T
pointer_byte_offsets
#96283)使用环绕算法计算与指针的偏移量 (以字节为单位)。
(便于 .wrapping_byte_offset(计为 isize)
)
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 wrapping_add。
请参见该方法以获取文档。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.61.0) · sourcepub const fn wrapping_sub(self, count: usize) -> *mut T
pub const fn wrapping_sub(self, count: usize) -> *mut T
使用换行算法计算与指针的偏移量。
(为 .wrapping_offset((count as isize).wrapping_neg())
带来的便利)
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
此操作本身始终是安全的,但使用结果指针则不安全。
结果指针 “remembers” 是 self
指向的 分配对象; 它不得用于读取或写入其他分配的对象。
换句话说,即使我们假设 T
的大小为 1
并且没有溢出,let z = x.wrapping_sub((x as usize) - (y as usize))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 sub
相比,此方法从根本上延迟了留在同一分配对象内的需求: sub
是跨越对象边界时的立即未定义行为; wrapping_sub
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
sub
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
// 使用裸指针以两个元素 (backwards) 为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let start_rounded_down = ptr.wrapping_sub(2);
ptr = ptr.wrapping_add(4);
let step = 2;
// 此循环打印 "5, 3, 1, "
while ptr != start_rounded_down {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_sub(step);
}
Runconst: unstable · sourcepub fn wrapping_byte_sub(self, count: usize) -> *mut T
🔬This is a nightly-only experimental API. (pointer_byte_offsets
#96283)
pub fn wrapping_byte_sub(self, count: usize) -> *mut T
pointer_byte_offsets
#96283)使用环绕算法计算与指针的偏移量 (以字节为单位)。
(为 .wrapping_offset((count as isize).wrapping_neg())
带来的便利)
count
以字节为单位。
这纯粹是为了方便转换为 u8
指针并在其上使用 wrapping_sub。
请参见该方法以获取文档。
对于非 Sized
指针,此操作仅更改数据指针,而保留元数据不变。
1.26.0 (const: 1.71.0) · sourcepub const unsafe fn read(self) -> T
pub const unsafe fn read(self) -> T
从 self
读取值而不移动它。
这将使 self
中的内存保持不变。
有关安全性问题和示例,请参见 ptr::read
。
1.26.0 · sourcepub unsafe fn read_volatile(self) -> T
pub unsafe fn read_volatile(self) -> T
对 self
的值进行易失性读取,而无需移动它。这将使 self
中的内存保持不变。
易失性操作旨在作用于 I/O 存储器,并保证编译器不会在其他易失性操作中对易失性操作进行清除或重新排序。
有关安全性问题和示例,请参见 ptr::read_volatile
。
1.26.0 (const: 1.71.0) · sourcepub const unsafe fn read_unaligned(self) -> T
pub const unsafe fn read_unaligned(self) -> T
1.26.0 (const: 1.63.0) · sourcepub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
将 count * size_of<T>
字节从 self
复制到 dest
。
源和目标可能 不 重叠。
NOTE: 这与 ptr::copy_nonoverlapping
具有相同的参数顺序。
有关安全性问题和示例,请参见 ptr::copy_nonoverlapping
。
1.26.0 (const: 1.63.0) · sourcepub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
将 count * size_of<T>
字节从 src
复制到 self
。
源和目标可能 不 重叠。
NOTE: 这具有 ptr::copy_nonoverlapping
的 相反 参数顺序。
有关安全性问题和示例,请参见 ptr::copy_nonoverlapping
。
1.26.0 · sourcepub unsafe fn drop_in_place(self)
pub unsafe fn drop_in_place(self)
执行指向值的析构函数 (如果有)。
有关安全性问题和示例,请参见 ptr::drop_in_place
。
1.26.0 (const: unstable) · sourcepub unsafe fn write(self, val: T)
pub unsafe fn write(self, val: T)
用给定值覆盖存储位置,而无需读取或丢弃旧值。
有关安全性问题和示例,请参见 ptr::write
。
1.26.0 (const: unstable) · sourcepub unsafe fn write_bytes(self, val: u8, count: usize)
pub unsafe fn write_bytes(self, val: u8, count: usize)
在指定的指针上调用 memset,将 self
开始的 count * size_of::<T>()
内存字节设置为 val
。
有关安全性问题和示例,请参见 ptr::write_bytes
。
1.26.0 · sourcepub unsafe fn write_volatile(self, val: T)
pub unsafe fn write_volatile(self, val: T)
使用给定值对存储单元执行易失性写操作,而无需读取或丢弃旧值。
易失性操作旨在作用于 I/O 存储器,并保证编译器不会在其他易失性操作中对易失性操作进行清除或重新排序。
有关安全性问题和示例,请参见 ptr::write_volatile
。
1.26.0 (const: unstable) · sourcepub unsafe fn write_unaligned(self, val: T)
pub unsafe fn write_unaligned(self, val: T)
1.26.0 · sourcepub unsafe fn replace(self, src: T) -> T
pub unsafe fn replace(self, src: T) -> T
用 src
替换 self
处的值,返回旧值,但不丢弃任何一个。
有关安全性问题和示例,请参见 ptr::replace
。
1.26.0 (const: unstable) · sourcepub unsafe fn swap(self, with: *mut T)
pub unsafe fn swap(self, with: *mut T)
在相同类型的两个可变位置交换值,而无需取消初始化任何一个。
它们可能重叠,这与 mem::swap
不同,后者在其他方面是等效的。
有关安全性问题和示例,请参见 ptr::swap
。
1.36.0 (const: unstable) · sourcepub fn align_offset(self, align: usize) -> usize
pub fn align_offset(self, align: usize) -> usize
计算为使其与 align
对齐而需要应用到指针的偏移量。
如果无法对齐指针,则实现将返回 usize::MAX
。
允许实现 始终 返回 usize::MAX
。
只有算法的性能可以取决于此处是否可获得可用的偏移量,而不取决于其正确性。
偏移量以 T
元素的数量表示,而不是以字节表示。返回的值可以与 wrapping_add
方法一起使用。
不能保证偏移指针不会溢出或超出指针所指向的分配范围。
调用者应确保返回的偏移量在对齐方式以外的所有方面都是正确的。
Panics
如果 align
不是 2 的幂,则函数 panics。
Examples
将相邻的 u8
作为 u16
进行访问
use std::mem::align_of;
let mut x = [5_u8, 6, 7, 8, 9];
let ptr = x.as_mut_ptr();
let offset = ptr.align_offset(align_of::<u16>());
if offset < x.len() - 1 {
let u16_ptr = ptr.add(offset).cast::<u16>();
*u16_ptr = 0;
assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]);
} else {
// 虽然指针可以通过 `offset` 对齐,但它会指向分配之外
}
Runconst: unstable · sourcepub fn is_aligned(self) -> bool
🔬This is a nightly-only experimental API. (pointer_is_aligned
#96284)
pub fn is_aligned(self) -> bool
pointer_is_aligned
#96284)返回指针是否为 T
正确对齐。
Examples
#![feature(pointer_is_aligned)]
#![feature(pointer_byte_offsets)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
let mut data = AlignedI32(42);
let ptr = &mut data as *mut AlignedI32;
assert!(ptr.is_aligned());
assert!(!ptr.wrapping_byte_add(1).is_aligned());
Run在编译时
Note: 编译时的对齐是实验性的,可能会发生变化。有关详细信息,请参见 tracking issue。
在编译时,编译器可能不知道值将在内存中的何处结束。
在编译时对从引用创建的指针调用此函数将仅在保证指针对齐的情况下返回 true
。
这意味着如果将指针转换为比引用的底层分配具有更严格对齐的类型,则指针永远不会对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
#![feature(const_mut_refs)]
// 在某些平台上,图元的对齐方式小于它们的大小。
#[repr(align(4))]
struct AlignedI32(i32);
#[repr(align(8))]
struct AlignedI64(i64);
const _: () = {
let mut data = AlignedI32(42);
let ptr = &mut data as *mut AlignedI32;
assert!(ptr.is_aligned());
// 在运行时 `ptr1` 或 `ptr2` 将对齐,但在编译时两者都不对齐。
let ptr1 = ptr.cast::<AlignedI64>();
let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
assert!(!ptr1.is_aligned());
assert!(!ptr2.is_aligned());
};
Run由于此行为,即使编译时指针未对齐,派生自编译时指针的运行时指针也可能对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,图元的对齐方式小于它们的大小。
#[repr(align(4))]
struct AlignedI32(i32);
#[repr(align(8))]
struct AlignedI64(i64);
// 在编译时,`COMPTIME_PTR` 和 `COMPTIME_PTR + 1` 都没有对齐。
// 另请注意,可变引用不允许出现在常量的最终值中。
const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut();
const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
// 在运行时,`runtime_ptr` 或 `runtime_ptr + 1` 对齐。
let runtime_ptr = COMPTIME_PTR;
assert_ne!(
runtime_ptr.cast::<AlignedI64>().is_aligned(),
runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
);
Run如果指针是从固定地址创建的,则此函数在运行时和编译时的行为相同。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,图元的对齐方式小于它们的大小。
#[repr(align(4))]
struct AlignedI32(i32);
#[repr(align(8))]
struct AlignedI64(i64);
const _: () = {
let ptr = 40 as *mut AlignedI32;
assert!(ptr.is_aligned());
// 对于具有已知地址的指针,运行时和编译时行为是相同的。
let ptr1 = ptr.cast::<AlignedI64>();
let ptr2 = ptr.wrapping_add(1).cast::<AlignedI64>();
assert!(ptr1.is_aligned());
assert!(!ptr2.is_aligned());
};
Runconst: unstable · sourcepub fn is_aligned_to(self, align: usize) -> bool
🔬This is a nightly-only experimental API. (pointer_is_aligned
#96284)
pub fn is_aligned_to(self, align: usize) -> bool
pointer_is_aligned
#96284)返回指针是否与 align
对齐。
对于非 Sized
指针,此操作仅考虑数据指针,而忽略元数据。
Panics
如果 align
不是 2 的幂 (包括 0),函数会出现 panic。
Examples
#![feature(pointer_is_aligned)]
#![feature(pointer_byte_offsets)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
let mut data = AlignedI32(42);
let ptr = &mut data as *mut AlignedI32;
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
Run在编译时
Note: 编译时的对齐是实验性的,可能会发生变化。有关详细信息,请参见 tracking issue。
在编译时,编译器可能不知道值将在内存中的何处结束。
在编译时对从引用创建的指针调用此函数将仅在保证指针对齐的情况下返回 true
。
这意味着指针不能比引用的底层分配更严格地对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
#![feature(const_mut_refs)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
const _: () = {
let mut data = AlignedI32(42);
let ptr = &mut data as *mut AlignedI32;
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
// 在编译时,我们确定指针没有对齐到 8.
assert!(!ptr.is_aligned_to(8));
assert!(!ptr.wrapping_add(1).is_aligned_to(8));
};
Run由于此行为,即使编译时指针未对齐,派生自编译时指针的运行时指针也可能对齐。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
// 在某些平台上,i32 的对齐小于 4.
#[repr(align(4))]
struct AlignedI32(i32);
// 在编译时,`COMPTIME_PTR` 和 `COMPTIME_PTR + 1` 都没有对齐。
// 另请注意,可变引用不允许出现在常量的最终值中。
const COMPTIME_PTR: *mut AlignedI32 = (&AlignedI32(42) as *const AlignedI32).cast_mut();
const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
// 在运行时,`runtime_ptr` 或 `runtime_ptr + 1` 对齐。
let runtime_ptr = COMPTIME_PTR;
assert_ne!(
runtime_ptr.is_aligned_to(8),
runtime_ptr.wrapping_add(1).is_aligned_to(8),
);
Run如果指针是从固定地址创建的,则此函数在运行时和编译时的行为相同。
#![feature(pointer_is_aligned)]
#![feature(const_pointer_is_aligned)]
const _: () = {
let ptr = 40 as *mut u8;
assert!(ptr.is_aligned_to(1));
assert!(ptr.is_aligned_to(2));
assert!(ptr.is_aligned_to(4));
assert!(ptr.is_aligned_to(8));
assert!(!ptr.is_aligned_to(16));
};
Runsource§impl<T> *mut [T]
impl<T> *mut [T]
const: unstable · sourcepub fn len(self) -> usize
🔬This is a nightly-only experimental API. (slice_ptr_len
#71146)
pub fn len(self) -> usize
slice_ptr_len
#71146)const: unstable · sourcepub fn is_empty(self) -> bool
🔬This is a nightly-only experimental API. (slice_ptr_len
#71146)
pub fn is_empty(self) -> bool
slice_ptr_len
#71146)sourcepub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T])
🔬This is a nightly-only experimental API. (raw_slice_split
#95595)
pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T])
raw_slice_split
#95595)在索引处将一个线性原始切片分成两部分。
第一个将包含 [0, mid)
的所有索引 (不包括索引 mid
本身),第二个将包含 [mid, len)
的所有索引 (不包括索引 len
本身)。
Panics
如果为 mid > len
,就会出现 panics。
Safety
mid
必须是底层 allocated object 的 in-bounds。
这意味着 self
必须是可解引用的,并且跨越一个至少 mid * size_of::<T>()
字节长的分配。
不支持这些要求是 undefined behavior,即使不使用结果指针。
由于 len
在边界内,它不是 *mut [T]
的安全不,变体,因此此方法的安全要求与 split_at_mut_unchecked
相同。
显式边界检查仅在 len
正确时才有用。
Examples
#![feature(raw_slice_split)]
#![feature(slice_ptr_get)]
let mut v = [1, 0, 3, 0, 5, 6];
let ptr = &mut v as *mut [_];
unsafe {
let (left, right) = ptr.split_at_mut(2);
assert_eq!(&*left, [1, 0]);
assert_eq!(&*right, [3, 0, 5, 6]);
}
Runsourcepub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T])
🔬This is a nightly-only experimental API. (raw_slice_split
#95595)
pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T])
raw_slice_split
#95595)在索引处将一个原始切片分成两部分,而不进行边界检查。
第一个将包含 [0, mid)
的所有索引 (不包括索引 mid
本身),第二个将包含 [mid, len)
的所有索引 (不包括索引 len
本身)。
Safety
mid
必须是底层 [allocated object] 的 in-bounds。
这意味着 self
必须是可解引用的,并且跨越一个至少 mid * size_of::<T>()
字节长的分配。
不支持这些要求是 undefined behavior,即使不使用结果指针。
Examples
#![feature(raw_slice_split)]
let mut v = [1, 0, 3, 0, 5, 6];
// 限制借用的生命周期
unsafe {
let ptr = &mut v as *mut [_];
let (left, right) = ptr.split_at_mut_unchecked(2);
assert_eq!(&*left, [1, 0]);
assert_eq!(&*right, [3, 0, 5, 6]);
(&mut *left)[1] = 2;
(&mut *right)[1] = 4;
}
assert_eq!(v, [1, 2, 3, 4, 5, 6]);
Runconst: unstable · sourcepub fn as_mut_ptr(self) -> *mut T
🔬This is a nightly-only experimental API. (slice_ptr_get
#74265)
pub fn as_mut_ptr(self) -> *mut T
slice_ptr_get
#74265)sourcepub unsafe fn get_unchecked_mut<I>(
self,
index: I
) -> *mut <I as SliceIndex<[T]>>::Outputwhere
I: SliceIndex<[T]>,
🔬This is a nightly-only experimental API. (slice_ptr_get
#74265)
pub unsafe fn get_unchecked_mut<I>( self, index: I ) -> *mut <I as SliceIndex<[T]>>::Outputwhere I: SliceIndex<[T]>,
slice_ptr_get
#74265)将裸指针返回到元素或子切片,而不进行边界检查。
使用 out-of-bounds index 或当 self
不可解引用时调用此方法是 undefined behavior,即使未使用结果指针。
Examples
#![feature(slice_ptr_get)]
let x = &mut [1, 2, 4] as *mut [i32];
unsafe {
assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1));
}
Runconst: unstable · sourcepub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>
🔬This is a nightly-only experimental API. (ptr_as_uninit
#75402)
pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>
ptr_as_uninit
#75402)如果指针为空,则返回 None
,否则返回共享切片到 Some
中包装的值。
与 as_ref
相比,这不需要将该值初始化。
对于可变的对应物,请参见 as_uninit_slice_mut
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须为 有效 的,才能读取许多字节的
ptr.len() * mem::size_of::<T>()
,并且必须正确对齐。这尤其意味着:-
整个内存范围必须包含在单个 分配对象 内! 切片永远不能跨越多个分配的对象。
-
即使对于零长度的切片,指针也必须对齐。 这样做的一个原因是,枚举布局优化可能依赖于对齐的引用 (包括任何长度的切片) 和非空值,以将它们与其他数据区分开。
您可以使用
NonNull::dangling()
获得可用作零长度切片的data
的指针。 -
-
切片的总大小
ptr.len() * mem::size_of::<T>()
不能大于isize::MAX
。 请参见pointer::offset
的安全文档。 -
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能发生可变 (UnsafeCell
内部除外)。
即使未使用此方法的结果也是如此!
另请参见 slice::from_raw_parts
。
const: unstable · sourcepub unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit<T>]>
🔬This is a nightly-only experimental API. (ptr_as_uninit
#75402)
pub unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit<T>]>
ptr_as_uninit
#75402)如果指针为空,则返回 None
,否则返回一个唯一的切片到 Some
中包装的值。
与 as_mut
相比,这不需要将该值初始化。
有关共享副本,请参见 as_uninit_slice
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须是 有效 的才能进行
ptr.len() * mem::size_of::<T>()
多个字节的读取和写入,并且必须正确对齐。这尤其意味着:-
整个内存范围必须包含在单个 分配对象 内! 切片永远不能跨越多个分配的对象。
-
即使对于零长度的切片,指针也必须对齐。 这样做的一个原因是,枚举布局优化可能依赖于对齐的引用 (包括任何长度的切片) 和非空值,以将它们与其他数据区分开。
您可以使用
NonNull::dangling()
获得可用作零长度切片的data
的指针。 -
-
切片的总大小
ptr.len() * mem::size_of::<T>()
不能大于isize::MAX
。 请参见pointer::offset
的安全文档。 -
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能通过任何其他指针访问 (读取或写入)。
即使未使用此方法的结果也是如此!