Primitive Type pointer

1.0.0 ·
Expand description

原始的、不安全的指针 *const T*mut T

See also the std::ptr module.

在 Rust 中使用裸指针并不常见,通常仅限于几种模式。 裸指针可以是未对齐的或 null。但是,当解引用裸指针 (使用 * 运算符) 时,它必须为非 null 并对齐。

使用 *ptr = data 通过裸指针存储会在旧值上调用 drop,因此,如果该类型具有 drop glue 并且尚未初始化内存,则必须使用 write; 否则,将在未初始化的内存上调用 drop

使用 nullnull_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); // 不允许强制转换
Run

4. 从 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 中的 mallocfree,但是 C API 通常会发出很多指针,因此 Rust 中的裸指针常见来源。

Implementations§

source§

impl<T> *const [T]

const: unstable · source

pub fn len(self) -> usize

🔬This is a nightly-only experimental API. (slice_ptr_len #71146)

返回原始切片的长度。

返回的值是 元素 的数量,而不是字节数。

即使原始切片由于指针为空或未对齐而无法转换为切片引用,此函数也是安全的。

Examples
#![feature(slice_ptr_len)]

use std::ptr;

let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
assert_eq!(slice.len(), 3);
Run
const: unstable · source

pub fn as_ptr(self) -> *const T

🔬This is a nightly-only experimental API. (slice_ptr_get #74265)

将裸指针返回到切片的缓冲区。

这等效于将 self 强制转换为 *const T,但类型安全性更高。

Examples
#![feature(slice_ptr_get)]
use std::ptr;

let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
assert_eq!(slice.as_ptr(), ptr::null());
Run
source

pub 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)

将裸指针返回到元素或子切片,而不进行边界检查。

使用越界索引或当 self 不可解引用时调用此方法是 未定义行为,即使未使用结果指针。

Examples
#![feature(slice_ptr_get)]

let x = &[1, 2, 4] as *const [i32];

unsafe {
    assert_eq!(x.get_unchecked(1), x.as_ptr().add(1));
}
Run
const: unstable · source

pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>

🔬This is a nightly-only experimental API. (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,

const: unstable · source

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());
Run
1.38.0 (const: 1.38.0) · source

pub const fn cast<U>(self) -> *const U

强制转换为另一种类型的指针。

const: unstable · source

pub fn with_metadata_of<U>(self, meta: *const U) -> *const Uwhere U: ?Sized,

🔬This is a nightly-only experimental API. (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"
}
Run
1.65.0 (const: 1.65.0) · source

pub const fn cast_mut(self) -> *mut T

更改常量而不更改类型。

这比 as 安全一点,因为如果重构代码,它不会默默地改变类型。

source

pub 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)

将指针强制转换为原始位。

这等效于 as usize,但更具体以增强可读性。 相反的方法是 from_bits

特别是,*p as usizep 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);
Run
source

pub 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)

从其原始位创建一个指针。

这等效于 as *const T,但更具体地说是为了增强可读性。 相反的方法是 to_bits

Examples
#![feature(ptr_to_from_bits)]
use std::ptr::NonNull;
let dangling: *const u8 = NonNull::dangling().as_ptr();
assert_eq!(<*const u8>::from_bits(1), dangling);
Run
source

pub fn addr(self) -> usize

🔬This is a nightly-only experimental API. (strict_provenance #95228)

获取指针的 “address” 部分。

这类似于 self as usize,它在语义上丢弃了provenanceaddress-space 信息。 但是,与 self as usize 不同,将返回的地址转换回指针会产生 invalid,这对于解引用来说是未定义的行为。 要正确恢复丢失的信息并获得可解引用的指针,请使用 with_addrmap_addr

如果由于无法保留具有所需出处的指针而无法使用这些 API,请改用 expose_addrfrom_exposed_addr

但是,请注意,这会降低您的代码的可移植性,并且不太适合用于检查是否符合 Rust 内存模型的工具。

在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。 需要在指针中存储附加信息的平台可以执行表示的改变,以产生仅包含指针的地址部分的值。 这意味着什么取决于平台来定义。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,因此可能会在 future 中发生变化 (包括可能削弱这一点,使其完全等同于 self as usize)。 有关详细信息,请参见 [模块文档

source

pub fn expose_addr(self) -> usize

🔬This is a nightly-only experimental API. (strict_provenance #95228)

获取指针的 “address” 部分,并暴露 “provenance” 部分,以便将来在 from_exposed_addr 中使用。

这相当于 self as usize,它在语义上丢弃了 provenanceaddress-space 信息。 此外,这 (如 as cast 一样) 具有将出处标记为 ‘exposed’ 的隐式副作用,因此在支持它的平台上,您可以稍后调用 from_exposed_addr 来重构原始指针,包括其出处。

(如果需要,重建地址空间信息是您的责任。)

使用这种方法意味着代码没有遵循严格的出处规则。 支持 from_exposed_addr 会使规范和推理复杂化,并且可能不受帮助您与 Rust 内存模型保持一致的工具的支持,因此建议尽可能使用 addr

在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。 需要在指针中存储附加信息的平台可能不支持此操作,因为 from_exposed_addr 工作所需的 ‘expose’ 副作用通常不可用。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档

source

pub fn with_addr(self, addr: usize) -> *const T

🔬This is a nightly-only experimental API. (strict_provenance #95228)

使用给定地址创建一个新指针。

这执行与 addr as ptr 强制转换相同的操作,但将 selfaddress-spaceprovenance 复制到新指针。 这使我们能够动态地保存和传播这些重要信息,而这在其他情况下使用一元强制转换是不可能的。

这相当于使用 wrapping_offsetself 偏移到给定地址,因此具有所有相同的功能和限制。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档

source

pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> *const T

🔬This is a nightly-only experimental API. (strict_provenance #95228)

通过将 self 的地址映射到新地址来创建新指针。

这对 with_addr 来说是一种方便,有关详细信息,请参见该方法。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档

const: unstable · source

pub fn to_raw_parts(self) -> (*const (), <T as Pointee>::Metadata)

🔬This is a nightly-only experimental API. (ptr_metadata #81513)

将指针 (可能是宽指针) 分解为其地址和元数据组件。

以后可以使用 from_raw_parts 重建指针。

1.9.0 (const: unstable) · source

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}!");
}
Run
const: unstable · source

pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>

🔬This is a nightly-only experimental API. (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());
    }
}
Run
const: 1.61.0 · source

pub const unsafe fn offset(self, count: isize) -> *const T

计算与指针的偏移量。

count 以 T 为单位; 例如,count 为 3 表示 3 * size_of::<T>() 字节的指针偏移量。

Safety

如果违反以下任一条件,则结果为未定义行为:

  • 起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。

  • 计算的偏移量 (以字节为单位) 不会使 isize 溢出。

  • 偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度总和 (以字节为单位) 必须适合于 usize。

编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不会超过 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);
}
Run
const: unstable · source

pub unsafe fn byte_offset(self, count: isize) -> *const T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

计算与指针的偏移量 (以字节为单位)。

count字节 为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 offset。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.16.0 (const: 1.61.0) · source

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)) 不会使 zy 相同: z 仍附加到对象 x 所附加的对象,并且解引用它是 Undefined Behavior,除非 xy 指向同一分配的对象。

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);
}
Run
const: unstable · source

pub fn wrapping_byte_offset(self, count: isize) -> *const T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

使用环绕算法计算与指针的偏移量 (以字节为单位)。

count字节 为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 wrapping_offset。 请参见该方法以获取文档。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

source

pub fn mask(self, mask: usize) -> *const T

🔬This is a nightly-only experimental API. (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);
Run
1.47.0 (const: 1.65.0) · source

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 的某个值内的两个指针将始终满足最后两个条件。

标准库通常还确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不超过 isize::MAX 字节,因此 ptr_into_vec.offset_from(vec.as_ptr()) 始终满足最后两个条件。

从根本上说,大多数平台甚至都无法构建如此大的分配。 例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。 但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX 字节的请求提供服务。 因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。 (请注意,offsetadd 也具有类似的限制,因此也不能在如此大的分配上使用。)

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); // 未定义的行为
}
Run
const: unstable · source

pub unsafe fn byte_offset_from<U>(self, origin: *const U) -> isizewhere U: ?Sized,

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

计算两个指针之间的距离。返回值以 字节 为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 offset_from。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅考虑数据指针,忽略元数据。

const: unstable · source

pub unsafe fn sub_ptr(self, origin: *const T) -> usize

🔬This is a nightly-only experimental API. (ptr_sub_ptr #95892)

计算两个指针之间的距离,where 已知 self 等于或大于 origin。返回值以 T 为单位: 以字节为单位的距离除以 mem::size_of::<T>()

这将计算 offset_from 将计算的相同值,但附加的前提条件是偏移量保证为非 negative。 此方法等同于 usize::try_from(self.offset_from(origin)).unwrap_unchecked(),但它为优化器提供了更多的信息,这有时可以使其在某些后端优化得更好。

这个方法可以看作是恢复传递给 addcount (或者,使用其他顺序的参数,到 sub). 以下都是等价的,假设它们的安全先决条件得到满足:

ptr.sub_ptr(origin) == count
origin.add(count) == ptr
ptr.sub(count) == origin
Run
Safety
  • 指针之间的距离必须是非 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)
Run
const: unstable · source

pub fn guaranteed_eq(self, other: *const T) -> Option<bool>

🔬This is a nightly-only experimental API. (const_raw_ptr_comparison #53020)

返回两个指针是否保证相等。

在运行时,这个函数的行为类似于 Some(self == other)。 但是,在某些情况下 (例如,编译时评估),并不总是可以确定两个指针的相等性,因此该函数可能会虚假地返回 None 以获取稍后实际上证明其相等性已知的指针。

但是当它返回 Some 时,可以保证知道指针的相等性。

返回值可能会从 Some 更改为 None,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。 建议仅将此函数用于性能优化,其中此函数的虚假 None 返回值不会影响结果,而只会影响性能。 尚未探讨使用此方法使运行时和编译时代码表现不同的后果。 不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。

const: unstable · source

pub fn guaranteed_ne(self, other: *const T) -> Option<bool>

🔬This is a nightly-only experimental API. (const_raw_ptr_comparison #53020)

返回是否保证两个指针不相等。

在运行时,这个函数的行为类似于 Some(self != other)。 然而,在某些情况下 (例如,编译时求值),并不总是可以确定两个指针的不等式,因此该函数可能会虚假地返回 None 以获取后来实际证明其不等式的指针。

但是当它返回 Some 时,指针的不等式保证是已知的。

返回值可能会从 Some 更改为 None,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。 建议仅将此函数用于性能优化,其中此函数的虚假 None 返回值不会影响结果,而只会影响性能。 尚未探讨使用此方法使运行时和编译时代码表现不同的后果。 不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。

1.26.0 (const: 1.61.0) · source

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

编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不会超过 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);
}
Run
const: unstable · source

pub unsafe fn byte_add(self, count: usize) -> *const T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

以字节为单位计算指针的偏移量 (方便 .byte_offset(count as isize))。

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 add。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.61.0) · source

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” 地址空间。也就是说,无限精度的总和必须符合使用大小。

编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不会超过 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);
}
Run
const: unstable · source

pub unsafe fn byte_sub(self, count: usize) -> *const T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

以字节为单位计算指针的偏移量 (方便 .byte_offset((count as isize).wrapping_neg()))。

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 sub。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.61.0) · source

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)) 不会使 zy 相同: z 仍附加到对象 x 所附加的对象,并且解引用它是 Undefined Behavior,除非 xy 指向同一分配的对象。

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);
}
Run
const: unstable · source

pub fn wrapping_byte_add(self, count: usize) -> *const T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

使用环绕算法计算与指针的偏移量 (以字节为单位)。 (便于 .wrapping_byte_offset(计为 isize))

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 wrapping_add。 请参见该方法以获取文档。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.61.0) · source

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)) 不会使 zy 相同: z 仍附加到对象 x 所附加的对象,并且解引用它是 Undefined Behavior,除非 xy 指向同一分配的对象。

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);
}
Run
const: unstable · source

pub fn wrapping_byte_sub(self, count: usize) -> *const T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

使用环绕算法计算与指针的偏移量 (以字节为单位)。 (为 .wrapping_offset((count as isize).wrapping_neg()) 带来的便利)

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 wrapping_sub。 请参见该方法以获取文档。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.71.0) · source

pub const unsafe fn read(self) -> T

self 读取值而不移动它。 这将使 self 中的内存保持不变。

有关安全性问题和示例,请参见 ptr::read

1.26.0 · source

pub unsafe fn read_volatile(self) -> T

self 的值进行易失性读取,而无需移动它。这将使 self 中的内存保持不变。

易失性操作旨在作用于 I/O 存储器,并保证编译器不会在其他易失性操作中对易失性操作进行清除或重新排序。

有关安全性问题和示例,请参见 ptr::read_volatile

1.26.0 (const: 1.71.0) · source

pub const unsafe fn read_unaligned(self) -> T

self 读取值而不移动它。 这将使 self 中的内存保持不变。

read 不同,指针可能未对齐。

有关安全性问题和示例,请参见 ptr::read_unaligned

1.26.0 (const: 1.63.0) · source

pub const unsafe fn copy_to(self, dest: *mut T, count: usize)

count * size_of<T> 字节从 self 复制到 dest。 源和目标可能会重叠。

NOTE: 这与 ptr::copy 具有相同的参数顺序。

有关安全性问题和示例,请参见 ptr::copy

1.26.0 (const: 1.63.0) · source

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) · source

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` 对齐,但它会指向分配之外
}
Run
const: unstable · source

pub fn is_aligned(self) -> bool

🔬This is a nightly-only experimental API. (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());
};
Run
const: unstable · source

pub fn is_aligned_to(self, align: usize) -> bool

🔬This is a nightly-only experimental API. (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));
};
Run
source§

impl<T> *mut Twhere T: ?Sized,

const: unstable · source

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());
Run
1.38.0 (const: 1.38.0) · source

pub const fn cast<U>(self) -> *mut U

强制转换为另一种类型的指针。

const: unstable · source

pub fn with_metadata_of<U>(self, meta: *const U) -> *mut Uwhere U: ?Sized,

🔬This is a nightly-only experimental API. (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"
}
Run
1.65.0 (const: 1.65.0) · source

pub const fn cast_const(self) -> *const T

更改常量而不更改类型。

这比 as 安全一点,因为如果重构代码,它不会默默地改变类型。

虽然不是严格要求 (*mut T 强制转换为 *const T),但这是为了与 *const T 上的 cast_mut 对称而提供的,如果使用它来代替隐式强制,则可能具有文档值。

source

pub 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)

将指针强制转换为原始位。

这等效于 as usize,但更具体以增强可读性。 相反的方法是 from_bits

特别是,*p as usizep 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);
}
Run
source

pub 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)

从其原始位创建一个指针。

这等效于 as *mut T,但更具体以增强可读性。 相反的方法是 to_bits

Examples
#![feature(ptr_to_from_bits)]
use std::ptr::NonNull;
let dangling: *mut u8 = NonNull::dangling().as_ptr();
assert_eq!(<*mut u8>::from_bits(1), dangling);
}
Run
source

pub fn addr(self) -> usize

🔬This is a nightly-only experimental API. (strict_provenance #95228)

获取指针的 “address” 部分。

这类似于 self as usize,它在语义上丢弃了provenanceaddress-space 信息。 但是,与 self as usize 不同,将返回的地址转换回指针会产生 invalid,这对于解引用来说是未定义的行为。 要正确恢复丢失的信息并获得可解引用的指针,请使用 with_addrmap_addr

如果由于无法保留具有所需出处的指针而无法使用这些 API,请改用 expose_addrfrom_exposed_addr_mut

但是,请注意,这会降低您的代码的可移植性,并且不太适合用于检查是否符合 Rust 内存模型的工具。

在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。 需要在指针中存储附加信息的平台可以执行表示的改变,以产生仅包含指针的地址部分的值。 这意味着什么取决于平台来定义。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,因此可能会在 future 中发生变化 (包括可能削弱这一点,使其完全等同于 self as usize)。 有关详细信息,请参见 [模块文档

source

pub fn expose_addr(self) -> usize

🔬This is a nightly-only experimental API. (strict_provenance #95228)

获取指针的 “address” 部分,并暴露 “provenance” 部分,以便将来在 from_exposed_addr 中使用。

这相当于 self as usize,它在语义上丢弃了 provenanceaddress-space 信息。 此外,这 (如 as 演员表) 具有将出处标记为 ‘exposed’ 的隐式副作用,因此在支持它的平台上,您可以稍后调用 from_exposed_addr_mut 来重构原始指针,包括其出处。

(如果需要,重建地址空间信息是您的责任。)

使用这种方法意味着代码没有遵循严格的出处规则。 支持 from_exposed_addr_mut 会使规范和推理复杂化,并且可能不受帮助您与 Rust 内存模型保持一致的工具的支持,因此建议尽可能使用 addr

在大多数平台上,这将产生一个与原始指针具有相同字节的值,因为所有字节都专用于描述地址。 需要在指针中存储附加信息的平台可能不支持此操作,因为 from_exposed_addr_mut 工作所需的 ‘expose’ 副作用通常不可用。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档

source

pub fn with_addr(self, addr: usize) -> *mut T

🔬This is a nightly-only experimental API. (strict_provenance #95228)

使用给定地址创建一个新指针。

这执行与 addr as ptr 强制转换相同的操作,但将 selfaddress-spaceprovenance 复制到新指针。 这使我们能够动态地保存和传播这些重要信息,而这在其他情况下使用一元强制转换是不可能的。

这相当于使用 wrapping_offsetself 偏移到给定地址,因此具有所有相同的功能和限制。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档

source

pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> *mut T

🔬This is a nightly-only experimental API. (strict_provenance #95228)

通过将 self 的地址映射到新地址来创建新指针。

这对 with_addr 来说是一种方便,有关详细信息,请参见该方法。

此 API 及其声明的语义是 Strict Provenance 实验的一部分,有关详细信息,请参见 模块文档

const: unstable · source

pub fn to_raw_parts(self) -> (*mut (), <T as Pointee>::Metadata)

🔬This is a nightly-only experimental API. (ptr_metadata #81513)

将指针 (可能是宽指针) 分解为其地址和元数据组件。

以后可以使用 from_raw_parts_mut 重建指针。

1.9.0 (const: unstable) · source

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}!");
}
Run
const: unstable · source

pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>

🔬This is a nightly-only experimental API. (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());
    }
}
Run
const: 1.61.0 · source

pub const unsafe fn offset(self, count: isize) -> *mut T

计算与指针的偏移量。

count 以 T 为单位; 例如,count 为 3 表示 3 * size_of::<T>() 字节的指针偏移量。

Safety

如果违反以下任一条件,则结果为未定义行为:

  • 起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。

  • 计算的偏移量 (以字节为单位) 不会使 isize 溢出。

  • 偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度总和 (以字节为单位) 必须适合于 usize。

编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不会超过 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));
}
Run
const: unstable · source

pub unsafe fn byte_offset(self, count: isize) -> *mut T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

计算与指针的偏移量 (以字节为单位)。

count字节 为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 offset。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.16.0 (const: 1.61.0) · source

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)) 不会使 zy 相同: z 仍附加到对象 x 所附加的对象,并且解引用它是 Undefined Behavior,除非 xy 指向同一分配的对象。

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]);
Run
const: unstable · source

pub fn wrapping_byte_offset(self, count: isize) -> *mut T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

使用环绕算法计算与指针的偏移量 (以字节为单位)。

count字节 为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 wrapping_offset。 请参见该方法以获取文档。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

source

pub fn mask(self, mask: usize) -> *mut T

🔬This is a nightly-only experimental API. (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);
Run
1.9.0 (const: unstable) · source

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]"。
Run
const: unstable · source

pub unsafe fn as_uninit_mut<'a>(self) -> Option<&'a mut MaybeUninit<T>>

🔬This is a nightly-only experimental API. (ptr_as_uninit #75402)

如果指针为 null,则返回 None,否则返回 Some 中包装的值的唯一引用。 与 as_mut 相比,这不需要将该值初始化。

有关共享副本,请参见 as_uninit_ref

Safety

调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:

  • 指针必须正确对齐。

  • 模块的文档 中定义的含义上,它必须是 “dereferenceable”。

  • 您必须执行 Rust 的别名规则,因为返回的生命周期 'a 是任意选择的,不一定反映数据的实际生命周期。

    特别是,当这个引用存在时,指针指向的内存不能通过任何其他指针访问 (读取或写入)。

即使未使用此方法的结果也是如此!

const: unstable · source

pub fn guaranteed_eq(self, other: *mut T) -> Option<bool>

🔬This is a nightly-only experimental API. (const_raw_ptr_comparison #53020)

返回两个指针是否保证相等。

在运行时,这个函数的行为类似于 Some(self == other)。 但是,在某些情况下 (例如,编译时评估),并不总是可以确定两个指针的相等性,因此该函数可能会虚假地返回 None 以获取稍后实际上证明其相等性已知的指针。

但是当它返回 Some 时,可以保证知道指针的相等性。

返回值可能会从 Some 更改为 None,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。 建议仅将此函数用于性能优化,其中此函数的虚假 None 返回值不会影响结果,而只会影响性能。 尚未探讨使用此方法使运行时和编译时代码表现不同的后果。 不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。

const: unstable · source

pub fn guaranteed_ne(self, other: *mut T) -> Option<bool>

🔬This is a nightly-only experimental API. (const_raw_ptr_comparison #53020)

返回是否保证两个指针不相等。

在运行时,这个函数的行为类似于 Some(self != other)。 然而,在某些情况下 (例如,编译时求值),并不总是可以确定两个指针的不等式,因此该函数可能会虚假地返回 None 以获取后来实际证明其不等式的指针。

但是当它返回 Some 时,指针的不等式保证是已知的。

返回值可能会从 Some 更改为 None,反之亦然,具体取决于编译器版本,并且不安全的代码不能依赖此函数的结果来保证可靠性。 建议仅将此函数用于性能优化,其中此函数的虚假 None 返回值不会影响结果,而只会影响性能。 尚未探讨使用此方法使运行时和编译时代码表现不同的后果。 不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。

1.47.0 (const: 1.65.0) · source

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 的某个值内的两个指针将始终满足最后两个条件。

标准库通常还确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不超过 isize::MAX 字节,因此 ptr_into_vec.offset_from(vec.as_ptr()) 始终满足最后两个条件。

从根本上说,大多数平台甚至都无法构建如此大的分配。 例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。 但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX 字节的请求提供服务。 因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。 (请注意,offsetadd 也具有类似的限制,因此也不能在如此大的分配上使用。)

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); // 未定义的行为
}
Run
const: unstable · source

pub unsafe fn byte_offset_from<U>(self, origin: *const U) -> isizewhere U: ?Sized,

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

计算两个指针之间的距离。返回值以 字节 为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 offset_from。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅考虑数据指针,忽略元数据。

const: unstable · source

pub unsafe fn sub_ptr(self, origin: *const T) -> usize

🔬This is a nightly-only experimental API. (ptr_sub_ptr #95892)

计算两个指针之间的距离,where 已知 self 等于或大于 origin。返回值以 T 为单位: 以字节为单位的距离除以 mem::size_of::<T>()

这将计算 offset_from 将计算的相同值,但附加的前提条件是偏移量保证为非 negative。 此方法等同于 usize::try_from(self.offset_from(origin)).unwrap_unchecked(),但它为优化器提供了更多的信息,这有时可以使其在某些后端优化得更好。

这个方法可以看作是恢复传递给 addcount (或者,使用其他顺序的参数,到 sub). 以下都是等价的,假设它们的安全先决条件得到满足:

ptr.sub_ptr(origin) == count
origin.add(count) == ptr
ptr.sub(count) == origin
Run
Safety
  • 指针之间的距离必须是非 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)








Run
1.26.0 (const: 1.61.0) · source

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

编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不会超过 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);
}
Run
const: unstable · source

pub unsafe fn byte_add(self, count: usize) -> *mut T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

以字节为单位计算指针的偏移量 (方便 .byte_offset(count as isize))。

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 add。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.61.0) · source

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” 地址空间。也就是说,无限精度的总和必须符合使用大小。

编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。 例如,VecBox 确保它们分配的字节数永远不会超过 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);
}
Run
const: unstable · source

pub unsafe fn byte_sub(self, count: usize) -> *mut T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

以字节为单位计算指针的偏移量 (方便 .byte_offset((count as isize).wrapping_neg()))。

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 sub。 有关文档和安全要求,请参见该方法。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.61.0) · source

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)) 不会使 zy 相同: z 仍附加到对象 x 所附加的对象,并且解引用它是 Undefined Behavior,除非 xy 指向同一分配的对象。

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);
}
Run
const: unstable · source

pub fn wrapping_byte_add(self, count: usize) -> *mut T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

使用环绕算法计算与指针的偏移量 (以字节为单位)。 (便于 .wrapping_byte_offset(计为 isize))

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 wrapping_add。 请参见该方法以获取文档。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.61.0) · source

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)) 不会使 zy 相同: z 仍附加到对象 x 所附加的对象,并且解引用它是 Undefined Behavior,除非 xy 指向同一分配的对象。

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);
}
Run
const: unstable · source

pub fn wrapping_byte_sub(self, count: usize) -> *mut T

🔬This is a nightly-only experimental API. (pointer_byte_offsets #96283)

使用环绕算法计算与指针的偏移量 (以字节为单位)。 (为 .wrapping_offset((count as isize).wrapping_neg()) 带来的便利)

count 以字节为单位。

这纯粹是为了方便转换为 u8 指针并在其上使用 wrapping_sub。 请参见该方法以获取文档。

对于非 Sized 指针,此操作仅更改数据指针,而保留元数据不变。

1.26.0 (const: 1.71.0) · source

pub const unsafe fn read(self) -> T

self 读取值而不移动它。 这将使 self 中的内存保持不变。

有关安全性问题和示例,请参见 ptr::read

1.26.0 · source

pub unsafe fn read_volatile(self) -> T

self 的值进行易失性读取,而无需移动它。这将使 self 中的内存保持不变。

易失性操作旨在作用于 I/O 存储器,并保证编译器不会在其他易失性操作中对易失性操作进行清除或重新排序。

有关安全性问题和示例,请参见 ptr::read_volatile

1.26.0 (const: 1.71.0) · source

pub const unsafe fn read_unaligned(self) -> T

self 读取值而不移动它。 这将使 self 中的内存保持不变。

read 不同,指针可能未对齐。

有关安全性问题和示例,请参见 ptr::read_unaligned

1.26.0 (const: 1.63.0) · source

pub const unsafe fn copy_to(self, dest: *mut T, count: usize)

count * size_of<T> 字节从 self 复制到 dest。 源和目标可能会重叠。

NOTE: 这与 ptr::copy 具有相同的参数顺序。

有关安全性问题和示例,请参见 ptr::copy

1.26.0 (const: 1.63.0) · source

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) · source

pub const unsafe fn copy_from(self, src: *const T, count: usize)

count * size_of<T> 字节从 src 复制到 self。 源和目标可能会重叠。

NOTE: 这具有 ptr::copy相反 参数顺序。

有关安全性问题和示例,请参见 ptr::copy

1.26.0 (const: 1.63.0) · source

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 · source

pub unsafe fn drop_in_place(self)

执行指向值的析构函数 (如果有)。

有关安全性问题和示例,请参见 ptr::drop_in_place

1.26.0 (const: unstable) · source

pub unsafe fn write(self, val: T)

用给定值覆盖存储位置,而无需读取或丢弃旧值。

有关安全性问题和示例,请参见 ptr::write

1.26.0 (const: unstable) · source

pub unsafe fn write_bytes(self, val: u8, count: usize)

在指定的指针上调用 memset,将 self 开始的 count * size_of::<T>() 内存字节设置为 val

有关安全性问题和示例,请参见 ptr::write_bytes

1.26.0 · source

pub unsafe fn write_volatile(self, val: T)

使用给定值对存储单元执行易失性写操作,而无需读取或丢弃旧值。

易失性操作旨在作用于 I/O 存储器,并保证编译器不会在其他易失性操作中对易失性操作进行清除或重新排序。

有关安全性问题和示例,请参见 ptr::write_volatile

1.26.0 (const: unstable) · source

pub unsafe fn write_unaligned(self, val: T)

用给定值覆盖存储位置,而无需读取或丢弃旧值。

write 不同,指针可能未对齐。

有关安全性问题和示例,请参见 ptr::write_unaligned

1.26.0 · source

pub unsafe fn replace(self, src: T) -> T

src 替换 self 处的值,返回旧值,但不丢弃任何一个。

有关安全性问题和示例,请参见 ptr::replace

1.26.0 (const: unstable) · source

pub unsafe fn swap(self, with: *mut T)

在相同类型的两个可变位置交换值,而无需取消初始化任何一个。 它们可能重叠,这与 mem::swap 不同,后者在其他方面是等效的。

有关安全性问题和示例,请参见 ptr::swap

1.36.0 (const: unstable) · source

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` 对齐,但它会指向分配之外
}
Run
const: unstable · source

pub fn is_aligned(self) -> bool

🔬This is a nightly-only experimental API. (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());
};
Run
const: unstable · source

pub fn is_aligned_to(self, align: usize) -> bool

🔬This is a nightly-only experimental API. (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));
};
Run
source§

impl<T> *mut [T]

const: unstable · source

pub fn len(self) -> usize

🔬This is a nightly-only experimental API. (slice_ptr_len #71146)

返回原始切片的长度。

返回的值是 元素 的数量,而不是字节数。

即使原始切片由于指针为空或未对齐而无法转换为切片引用,此函数也是安全的。

Examples
#![feature(slice_ptr_len)]
use std::ptr;

let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
assert_eq!(slice.len(), 3);
Run
const: unstable · source

pub fn is_empty(self) -> bool

🔬This is a nightly-only experimental API. (slice_ptr_len #71146)

如果原始切片的长度为 0.

Examples
#![feature(slice_ptr_len)]

let mut a = [1, 2, 3];
let ptr = &mut a as *mut [_];
assert!(!ptr.is_empty());
Run
source

pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T])

🔬This is a nightly-only experimental API. (raw_slice_split #95595)

在索引处将一个线性原始切片分成两部分。

第一个将包含 [0, mid) 的所有索引 (不包括索引 mid 本身),第二个将包含 [mid, len) 的所有索引 (不包括索引 len 本身)。

Panics

如果为 mid > len,就会出现 panics。

Safety

mid 必须是底层 allocated objectin-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]);
}
Run
source

pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T])

🔬This is a nightly-only experimental API. (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]);
Run
const: unstable · source

pub fn as_mut_ptr(self) -> *mut T

🔬This is a nightly-only experimental API. (slice_ptr_get #74265)

将裸指针返回到切片的缓冲区。

这等效于将 self 强制转换为 *mut T,但类型安全性更高。

Examples
#![feature(slice_ptr_get)]
use std::ptr;

let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
assert_eq!(slice.as_mut_ptr(), ptr::null_mut());
Run
source

pub 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)

将裸指针返回到元素或子切片,而不进行边界检查。

使用 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));
}
Run
const: unstable · source

pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]>

🔬This is a nightly-only experimental API. (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 · source

pub unsafe fn as_uninit_slice_mut<'a>(self) -> Option<&'a mut [MaybeUninit<T>]>

🔬This is a nightly-only experimental API. (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 是任意选择的,不一定反映数据的实际生命周期。 特别是,当这个引用存在时,指针指向的内存不能通过任何其他指针访问 (读取或写入)。

即使未使用此方法的结果也是如此!

另请参见 slice::from_raw_parts_mut

Trait Implementations§

source§

impl<T> Clone for *const Twhere T: ?Sized,

source§

fn clone(&self) -> *const T

返回值的副本。 Read more
source§

fn clone_from(&mut self, source: &Self)

source 执行复制分配。 Read more
source§

impl<T> Clone for *mut Twhere T: ?Sized,

source§

fn clone(&self) -> *mut T

返回值的副本。 Read more
source§

fn clone_from(&mut self, source: &Self)

source 执行复制分配。 Read more
source§

impl<T> Debug for *const Twhere T: ?Sized,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

使用给定的格式化程序格式化该值。 Read more
source§

impl<T> Debug for *mut Twhere T: ?Sized,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

使用给定的格式化程序格式化该值。 Read more
1.23.0 · source§

impl<T> From<*mut T> for AtomicPtr<T>

source§

fn from(p: *mut T) -> AtomicPtr<T>

*mut T 转换为 AtomicPtr<T>

source§

impl<T> Hash for *const Twhere T: ?Sized,

source§

fn hash<H>(&self, state: &mut H)where H: Hasher,

将该值输入给定的 HasherRead more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where H: Hasher, Self: Sized,

将这种类型的切片送入给定的 Hasher 中。 Read more
source§

impl<T> Hash for *mut Twhere T: ?Sized,

source§

fn hash<H>(&self, state: &mut H)where H: Hasher,

将该值输入给定的 HasherRead more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where H: Hasher, Self: Sized,

将这种类型的切片送入给定的 Hasher 中。 Read more
source§

impl<T> Ord for *const Twhere T: ?Sized,

source§

fn cmp(&self, other: &*const T) -> Ordering

此方法返回 selfother 之间的 OrderingRead more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere Self: Sized,

比较并返回两个值中的最大值。 Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere Self: Sized,

比较并返回两个值中的最小值。 Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere Self: Sized + PartialOrd<Self>,

将值限制在某个时间间隔内。 Read more
source§

impl<T> Ord for *mut Twhere T: ?Sized,

source§

fn cmp(&self, other: &*mut T) -> Ordering

此方法返回 selfother 之间的 OrderingRead more
1.21.0 · source§

fn max(self, other: Self) -> Selfwhere Self: Sized,

比较并返回两个值中的最大值。 Read more
1.21.0 · source§

fn min(self, other: Self) -> Selfwhere Self: Sized,

比较并返回两个值中的最小值。 Read more
1.50.0 · source§

fn clamp(self, min: Self, max: Self) -> Selfwhere Self: Sized + PartialOrd<Self>,

将值限制在某个时间间隔内。 Read more
source§

impl<T> PartialEq<*const T> for *const Twhere T: ?Sized,

source§

fn eq(&self, other: &*const T) -> bool

此方法测试 selfother 值是否相等,并由 == 使用。
source§

fn ne(&self, other: &Rhs) -> bool

此方法测试 !=。 默认实现几乎总是足够的,并且不应在没有充分理由的情况下被覆盖。
source§

impl<T> PartialEq<*mut T> for *mut Twhere T: ?Sized,

source§

fn eq(&self, other: &*mut T) -> bool

此方法测试 selfother 值是否相等,并由 == 使用。
source§

fn ne(&self, other: &Rhs) -> bool

此方法测试 !=。 默认实现几乎总是足够的,并且不应在没有充分理由的情况下被覆盖。
source§

impl<T> PartialOrd<*const T> for *const Twhere T: ?Sized,

source§

fn partial_cmp(&self, other: &*const T) -> Option<Ordering>

如果存在,则此方法返回 selfother 值之间的顺序。 Read more
source§

fn lt(&self, other: &*const T) -> bool

此方法测试的内容少于 (对于 selfother),并且由 < 操作员使用。 Read more
source§

fn le(&self, other: &*const T) -> bool

此方法测试小于或等于 (对于 selfother),并且由 <= 运算符使用。 Read more
source§

fn gt(&self, other: &*const T) -> bool

此方法测试大于 (对于 selfother),并且由 > 操作员使用。 Read more
source§

fn ge(&self, other: &*const T) -> bool

此方法测试是否大于或等于 (对于 selfother),并且由 >= 运算符使用。 Read more
source§

impl<T> PartialOrd<*mut T> for *mut Twhere T: ?Sized,

source§

fn partial_cmp(&self, other: &*mut T) -> Option<Ordering>

如果存在,则此方法返回 selfother 值之间的顺序。 Read more
source§

fn lt(&self, other: &*mut T) -> bool

此方法测试的内容少于 (对于 selfother),并且由 < 操作员使用。 Read more
source§

fn le(&self, other: &*mut T) -> bool

此方法测试小于或等于 (对于 selfother),并且由 <= 运算符使用。 Read more
source§

fn gt(&self, other: &*mut T) -> bool

此方法测试大于 (对于 selfother),并且由 > 操作员使用。 Read more
source§

fn ge(&self, other: &*mut T) -> bool

此方法测试是否大于或等于 (对于 selfother),并且由 >= 运算符使用。 Read more
source§

impl<T> Pointer for *const Twhere T: ?Sized,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

使用给定的格式化程序格式化该值。
source§

impl<T> Pointer for *mut Twhere T: ?Sized,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

使用给定的格式化程序格式化该值。
source§

impl<T> SimdElement for *const Twhere T: Pointee<Metadata = ()>,

§

type Mask = isize

🔬This is a nightly-only experimental API. (portable_simd #86656)
此元素类型对应的掩码元素类型。
source§

impl<T> SimdElement for *mut Twhere T: Pointee<Metadata = ()>,

§

type Mask = isize

🔬This is a nightly-only experimental API. (portable_simd #86656)
此元素类型对应的掩码元素类型。
source§

impl<'a, T, U> CoerceUnsized<*const U> for &'a Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<'a, T, U> CoerceUnsized<*const U> for &'a mut Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<T, U> CoerceUnsized<*const U> for *const Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<T, U> CoerceUnsized<*const U> for *mut Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<'a, T, U> CoerceUnsized<*mut U> for &'a mut Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<T, U> CoerceUnsized<*mut U> for *mut Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<T> Copy for *const Twhere T: ?Sized,

source§

impl<T> Copy for *mut Twhere T: ?Sized,

source§

impl<T, U> DispatchFromDyn<*const U> for *const Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<T, U> DispatchFromDyn<*mut U> for *mut Twhere T: Unsize<U> + ?Sized, U: ?Sized,

source§

impl<T> Eq for *const Twhere T: ?Sized,

source§

impl<T> Eq for *mut Twhere T: ?Sized,

source§

impl<T> !Send for *const Twhere T: ?Sized,

source§

impl<T> !Send for *mut Twhere T: ?Sized,

source§

impl<T, U> SimdCastPtr<T> for *const Uwhere U: Pointee, T: Pointee<Metadata = <U as Pointee>::Metadata>,

source§

impl<T, U> SimdCastPtr<T> for *mut Uwhere U: Pointee, T: Pointee<Metadata = <U as Pointee>::Metadata>,

source§

impl<T> !Sync for *const Twhere T: ?Sized,

source§

impl<T> !Sync for *mut Twhere T: ?Sized,

1.38.0 · source§

impl<T> Unpin for *const Twhere T: ?Sized,

1.38.0 · source§

impl<T> Unpin for *mut Twhere T: ?Sized,

1.9.0 · source§

impl<T> UnwindSafe for *const Twhere T: RefUnwindSafe + ?Sized,

1.9.0 · source§

impl<T> UnwindSafe for *mut Twhere T: RefUnwindSafe + ?Sized,

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

获取 selfTypeIdRead more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

从拥有的值中一成不变地借用。 Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

从拥有的值中借用。 Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

返回未更改的参数。

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

调用 U::from(self)

也就是说,这种转换是 From<T> for U 实现选择执行的任何操作。

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

获得所有权后的结果类型。
source§

fn to_owned(&self) -> T

从借用的数据创建拥有的数据,通常是通过克隆。 Read more
source§

fn clone_into(&self, target: &mut T)

使用借来的数据来替换拥有的数据,通常是通过克隆。 Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

发生转换错误时返回的类型。
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

发生转换错误时返回的类型。
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。