Primitive Type pointer1.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 获取它。

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

如果指针为空,则返回 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

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

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

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

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

如果指针为空,则返回 None,否则返回 Some 中包装的值的共享引用。如果该值可能未初始化,则必须改用 as_uninit_ref

Safety

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

  • 指针必须正确对齐。

  • 模块文档 中定义的意义上,它必须是可解引用的。

  • 指针必须指向 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
🔬 This is a nightly-only experimental API. (ptr_as_uninit #75402)

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

Safety

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

  • 指针必须正确对齐。

  • 模块文档 中定义的意义上,它必须是可解引用的。

  • 您必须执行 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

计算与指针的偏移量。

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

使用换行算法计算与指针的偏移量。

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

计算两个指针之间的距离。返回的值以 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
🔬 This is a nightly-only experimental API. (const_raw_ptr_comparison #53020)

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

在运行时,此函数的行为类似于 self == other。 但是,在某些情况下 (例如,编译时评估),并非总是可以确定两个指针是否相等,因此此函数可能会虚假地返回 false 来表示后来实际上相等的指针。

但是,当它返回 true 时,保证指针是相等的。

该函数是 guaranteed_ne 的镜像,但不是其反函数。有两个指针返回 false 的指针比较。

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

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

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

在运行时,此函数的行为类似于 self != other。 但是,在某些情况下 (例如,编译时评估),并非总是可以确定两个指针的不相等性,因此此函数可能会虚假地返回 false 来表示后来实际上不相等的指针。

但是,当它返回 true 时,保证指针是不相等的。

该函数是 guaranteed_eq 的镜像,但不是其反函数。有两个指针返回 false 的指针比较。

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

计算与指针的偏移量 (.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

计算与指针的偏移量 (.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

使用换行算法计算与指针的偏移量。 (为 .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

使用换行算法计算与指针的偏移量。 (为 .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
🔬 This is a nightly-only experimental API. (set_ptr_value #75091)

将指针值设置为 ptr

如果 self 是指向未定义大小类型的 (fat) 指针,则此操作将仅影响指针部分,而对于指向已确定大小类型的 (thin) 指针,其作用与简单分配相同。

生成的指针将具有 val 的出处,即对于胖指针,此操作在语义上与使用 val 的数据指针值但 self 的元数据创建新的胖指针相同。

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 = ptr.set_ptr_value(thin.add(8));
    println!("{:?}", &*ptr); // 将打印 "3"
}
Run

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

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

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

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

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

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

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

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

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

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

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

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

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

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

计算为使其与 align 对齐而需要应用到指针的偏移量。

如果无法对齐指针,则实现将返回 usize::MAX。 允许实现 始终 返回 usize::MAX。 只有算法的性能可以取决于此处是否可获得可用的偏移量,而不取决于其正确性。

偏移量以 T 元素的数量表示,而不是以字节表示。返回的值可以与 wrapping_add 方法一起使用。

不能保证偏移指针不会溢出或超出指针所指向的分配范围。

调用者应确保返回的偏移量在对齐方式以外的所有方面都是正确的。

Panics

如果 align 不是 2 的幂,则函数 panics。

Examples

将相邻的 u8 作为 u16 进行访问

let x = [5u8, 6u8, 7u8, 8u8, 9u8];
let ptr = x.as_ptr().add(n) as *const u8;
let offset = ptr.align_offset(align_of::<u16>());
if offset < x.len() - n - 1 {
    let u16_ptr = ptr.add(offset) as *const u16;
    assert_ne!(*u16_ptr, 500);
} else {
    // 虽然指针可以通过 `offset` 对齐,但它会指向分配之外
}
Run
🔬 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
🔬 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(), 0 as *const i8);
Run
🔬 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
🔬 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

如果指针为空,则返回 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

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

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

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

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

如果指针为空,则返回 None,否则返回 Some 中包装的值的共享引用。如果该值可能未初始化,则必须改用 as_uninit_ref

对于可变的对应物,请参见 as_mut

Safety

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

  • 指针必须正确对齐。

  • 模块文档 中定义的意义上,它必须是可解引用的。

  • 指针必须指向 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
🔬 This is a nightly-only experimental API. (ptr_as_uninit #75402)

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

对于可变的对应物,请参见 as_uninit_mut

Safety

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

  • 指针必须正确对齐。

  • 模块文档 中定义的意义上,它必须是可解引用的。

  • 您必须执行 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

计算与指针的偏移量。

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

使用换行算法计算与指针的偏移量。 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

如果指针为 null,则返回 None,否则返回 Some 中包装的值的唯一引用。如果该值可能未初始化,则必须改用 as_uninit_mut

有关共享副本,请参见 as_ref

Safety

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

  • 指针必须正确对齐。

  • 模块文档 中定义的意义上,它必须是可解引用的。

  • 指针必须指向 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
🔬 This is a nightly-only experimental API. (ptr_as_uninit #75402)

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

有关共享副本,请参见 as_uninit_ref

Safety

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

  • 指针必须正确对齐。

  • 模块文档 中定义的意义上,它必须是可解引用的。

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

    特别是,在此生命周期的持续时间内,指针所指向的内存一定不能通过任何其他指针进行访问 (读取或写入)。

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

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

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

在运行时,此函数的行为类似于 self == other。 但是,在某些情况下 (例如,编译时评估),并非总是可以确定两个指针是否相等,因此此函数可能会虚假地返回 false 来表示后来实际上相等的指针。

但是,当它返回 true 时,保证指针是相等的。

该函数是 guaranteed_ne 的镜像,但不是其反函数。有两个指针返回 false 的指针比较。

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

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

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

在运行时,此函数的行为类似于 self != other。 但是,在某些情况下 (例如,编译时评估),并非总是可以确定两个指针的不相等性,因此此函数可能会虚假地返回 false 来表示后来实际上不相等的指针。

但是,当它返回 true 时,保证指针是不相等的。

该函数是 guaranteed_eq 的镜像,但不是其反函数。有两个指针返回 false 的指针比较。

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

计算两个指针之间的距离。返回的值以 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

计算与指针的偏移量 (.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

计算与指针的偏移量 (.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

使用换行算法计算与指针的偏移量。 (为 .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

使用换行算法计算与指针的偏移量。 (为 .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
🔬 This is a nightly-only experimental API. (set_ptr_value #75091)

将指针值设置为 ptr

如果 self 是指向未定义大小类型的 (fat) 指针,则此操作将仅影响指针部分,而对于指向已确定大小类型的 (thin) 指针,其作用与简单分配相同。

生成的指针将具有 val 的出处,即对于胖指针,此操作在语义上与使用 val 的数据指针值但 self 的元数据创建新的胖指针相同。

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 = ptr.set_ptr_value(thin.add(8));
    println!("{:?}", &*ptr); // 将打印 "3"
}
Run

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

计算为使其与 align 对齐而需要应用到指针的偏移量。

如果无法对齐指针,则实现将返回 usize::MAX。 允许实现 始终 返回 usize::MAX。 只有算法的性能可以取决于此处是否可获得可用的偏移量,而不取决于其正确性。

偏移量以 T 元素的数量表示,而不是以字节表示。返回的值可以与 wrapping_add 方法一起使用。

不能保证偏移指针不会溢出或超出指针所指向的分配范围。

调用者应确保返回的偏移量在对齐方式以外的所有方面都是正确的。

Panics

如果 align 不是 2 的幂,则函数 panics。

Examples

将相邻的 u8 作为 u16 进行访问

let x = [5u8, 6u8, 7u8, 8u8, 9u8];
let ptr = x.as_ptr().add(n) as *const u8;
let offset = ptr.align_offset(align_of::<u16>());
if offset < x.len() - n - 1 {
    let u16_ptr = ptr.add(offset) as *const u16;
    assert_ne!(*u16_ptr, 500);
} else {
    // 虽然指针可以通过 `offset` 对齐,但它会指向分配之外
}
Run
🔬 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
🔬 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(), 0 as *mut i8);
Run
🔬 This is a nightly-only experimental API. (slice_ptr_get #74265)

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

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

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
🔬 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

🔬 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

返回值的副本。 Read more

source 执行复制分配。 Read more

返回值的副本。 Read more

source 执行复制分配。 Read more

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

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

将该值输入给定的 HasherRead more

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

将该值输入给定的 HasherRead more

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

此方法返回 selfother 之间的 OrderingRead more

比较并返回两个值中的最大值。 Read more

比较并返回两个值中的最小值。 Read more

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

此方法返回 selfother 之间的 OrderingRead more

比较并返回两个值中的最大值。 Read more

比较并返回两个值中的最小值。 Read more

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

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

此方法测试 !=

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

此方法测试 !=

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

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

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

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

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

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

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

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

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

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

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

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