Primitive Type pointer1.0.0[−]
Expand description
原始的、不安全的指针 *const T
和 *mut T
。
在 Rust 中使用裸指针并不常见,通常仅限于几种模式。
裸指针可以是未对齐的或 null
。但是,当解引用裸指针 (使用 *
运算符) 时,它必须为非 null 并对齐。
使用 *ptr = data
通过裸指针存储会在旧值上调用 drop
,因此,如果该类型具有 drop glue 并且尚未初始化内存,则必须使用 write
; 否则,将在未初始化的内存上调用 drop
。
使用 null
和 null_mut
函数创建空指针,并使用 *const T
和 *mut T
类型的 is_null
方法检查空值。
*const T
和 *mut T
类型还定义了用于指针数学的 offset
方法。
创建裸指针的常用方法
1. 强制引用 (&T
) 或可变引用 (&mut T
)。
let my_num: i32 = 10;
let my_num_ptr: *const i32 = &my_num;
let mut my_speed: i32 = 88;
let my_speed_ptr: *mut i32 = &mut my_speed;
Run要获得指向 boxed 值的指针,请解引用 box:
let my_num: Box<i32> = Box::new(10);
let my_num_ptr: *const i32 = &*my_num;
let mut my_speed: Box<i32> = Box::new(88);
let my_speed_ptr: *mut i32 = &mut *my_speed;
Run这不会获得原始分配的所有权,并且以后不需要任何资源管理,但是您一定不能在其生命周期之后使用该指针。
2. 消费 box (Box<T>
)。
into_raw
函数消费 box 并返回裸指针。它不会销毁 T
或释放任何内存。
let my_speed: Box<i32> = Box::new(88);
let my_speed: *mut i32 = Box::into_raw(my_speed);
// 通过拥有原始 `Box<T>` 的所有权,我们有义务稍后将其放在一起销毁。
unsafe {
drop(Box::from_raw(my_speed));
}
Run请注意,此处对 drop
的调用是为了清楚起见 - 表示我们已经完成了给定值的操作,应将其销毁。
3. 使用 ptr::addr_of!
创建它
您可以使用宏 ptr::addr_of!
(对于 *const T
) 和 ptr::addr_of_mut!
(对于 *mut T
),而不是强制引用裸指针。
这些宏允许您创建裸指针指向您无法创建引用的字段 (不会导致未定义的行为),例如未对齐的字段。
如果涉及包装的结构或未初始化的内存,这可能是必要的。
#[derive(Debug, Default, Copy, Clone)]
#[repr(C, packed)]
struct S {
aligned: u8,
unaligned: u32,
}
let s = S::default();
let p = std::ptr::addr_of!(s.unaligned); // 不允许强制转换
Run4. 从 C 获取它。
extern crate libc;
use std::mem;
unsafe {
let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
if my_num.is_null() {
panic!("failed to allocate memory");
}
libc::free(my_num as *mut libc::c_void);
}
Run通常,您实际上不会使用 Rust 中的 malloc
和 free
,但是 C API 通常会发出很多指针,因此 Rust 中的裸指针常见来源。
Implementations
如果指针为空,则返回 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将指针强制转换为原始位。
这等效于 as usize
,但更具体以增强可读性。
相反的方法是 from_bits
。
特别是,*p as usize
和 p as usize
都会编译指向数字类型的指针,但做的事情却截然不同,因此使用它有助于强调读取位是有意的。
Examples
#![feature(ptr_to_from_bits)]
let array = [13, 42];
let p0: *const i32 = &array[0];
assert_eq!(<*const _>::from_bits(p0.to_bits()), p0);
let p1: *const i32 = &array[1];
assert_eq!(p1.to_bits() - p0.to_bits(), 4);
Run将指针 (可能是宽指针) 分解为其地址和元数据组件。
以后可以使用 from_raw_parts
重建指针。
如果指针为空,则返回 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如果指针为空,则返回 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计算与指针的偏移量。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度总和 (以字节为单位) 必须适合于 usize。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_offset
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
基本用法:
let s: &str = "123";
let ptr: *const u8 = s.as_ptr();
unsafe {
println!("{}", *ptr.offset(1) as char);
println!("{}", *ptr.offset(2) as char);
}
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))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 offset
相比,此方法从根本上延迟了留在同一分配对象内的需求: offset
是跨越对象边界时的立即未定义行为; wrapping_offset
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
offset
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
基本用法:
// 使用裸指针以两个元素为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_offset(6);
// 此循环打印 "1, 3, 5, "
while ptr != end_rounded_up {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_offset(step);
}
Run计算两个指针之间的距离。返回的值以 T 为单位:以字节为单位的距离除以 mem::size_of::<T>()
。
该函数是 offset
的逆函数。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和其他指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
两个指针必须是指向同一对象的指针的 *derived。 (请参见下面的示例。)
-
指针之间的距离 (以字节为单位) 必须是
T
大小的精确倍数。 -
指针之间的距离 (以字节为单位) 不会溢出
isize
。 -
该距离不能依赖于 “wrapping around” 地址空间。
Rust 类型从不大于 isize::MAX
,并且 Rust 分配从不环绕地址空间,因此,任何 Rust 类型 T
的某个值内的两个指针将始终满足最后两个条件。
标准库通常还确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不超过 isize::MAX
字节,因此 ptr_into_vec.offset_from(vec.as_ptr())
始终满足最后两个条件。
从根本上说,大多数平台甚至都无法构建如此大的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
(请注意,offset
和 add
也具有类似的限制,因此也不能在如此大的分配上使用。)
Panics
如果 T
是零大小类型 (“ZST”),则此函数 panics。
Examples
基本用法:
let a = [0; 5];
let ptr1: *const i32 = &a[1];
let ptr2: *const i32 = &a[3];
unsafe {
assert_eq!(ptr2.offset_from(ptr1), 2);
assert_eq!(ptr1.offset_from(ptr2), -2);
assert_eq!(ptr1.offset(2), ptr2);
assert_eq!(ptr2.offset(-2), ptr1);
}
Run不正确 用法:
let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8;
let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8;
let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
// 将 ptr2_other 设置为 ptr2 的 "alias",但从 ptr1 派生。
let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff);
assert_eq!(ptr2 as usize, ptr2_other as usize);
// 由于 ptr2_other 和 ptr2 是从指向不同对象的指针派生的,因此即使它们指向相同的地址,计算其偏移量也是未定义的行为!
unsafe {
let zero = ptr2_other.offset_from(ptr2); // 未定义的行为
}
Run返回两个指针是否保证相等。
在运行时,此函数的行为类似于 self == other
。
但是,在某些情况下 (例如,编译时评估),并非总是可以确定两个指针是否相等,因此此函数可能会虚假地返回 false
来表示后来实际上相等的指针。
但是,当它返回 true
时,保证指针是相等的。
该函数是 guaranteed_ne
的镜像,但不是其反函数。有两个指针返回 false
的指针比较。
返回值可能会根据编译器版本而改变,并且不安全的代码可能不依赖于这个函数的结果来保证稳健性。
建议仅将此函数用于性能优化,在这种情况下,此函数的虚假 false
返回值不会影响结果,而只会影响性能。
尚未探讨使用此方法使运行时和编译时代码表现不同的后果。
不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。
返回两个指针是否保证不相等。
在运行时,此函数的行为类似于 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
。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_add
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
基本用法:
let s: &str = "123";
let ptr: *const u8 = s.as_ptr();
unsafe {
println!("{}", *ptr.add(1) as char);
println!("{}", *ptr.add(2) as char);
}
Run计算与指针的偏移量 (.offset((count as isize).wrapping_neg())
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量不能超过
isize::MAX
个 字节。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合使用大小。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len()).sub(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_sub
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
基本用法:
let s: &str = "123";
unsafe {
let end: *const u8 = s.as_ptr().add(3);
println!("{}", *end.sub(1) as char);
println!("{}", *end.sub(2) as char);
}
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))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 add
相比,此方法从根本上延迟了留在同一分配对象内的需求: add
是跨越对象边界时的立即未定义行为; wrapping_add
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
add
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
基本用法:
// 使用裸指针以两个元素为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_add(6);
// 此循环打印 "1, 3, 5, "
while ptr != end_rounded_up {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_add(step);
}
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))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 sub
相比,此方法从根本上延迟了留在同一分配对象内的需求: sub
是跨越对象边界时的立即未定义行为; wrapping_sub
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
sub
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
基本用法:
// 使用裸指针以两个元素 (backwards) 为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let start_rounded_down = ptr.wrapping_sub(2);
ptr = ptr.wrapping_add(4);
let step = 2;
// 此循环打印 "5, 3, 1, "
while ptr != start_rounded_down {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_sub(step);
}
Run将指针值设置为 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
。
将 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如果指针为空,则返回 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将指针强制转换为原始位。
这等效于 as usize
,但更具体以增强可读性。
相反的方法是 from_bits
。
特别是,*p as usize
和 p as usize
都会编译指向数字类型的指针,但做的事情却截然不同,因此使用它有助于强调读取位是有意的。
Examples
#![feature(ptr_to_from_bits)]
let mut array = [13, 42];
let mut it = array.iter_mut();
let p0: *mut i32 = it.next().unwrap();
assert_eq!(<*mut _>::from_bits(p0.to_bits()), p0);
let p1: *mut i32 = it.next().unwrap();
assert_eq!(p1.to_bits() - p0.to_bits(), 4);
Run将指针 (可能是宽指针) 分解为其地址和元数据组件。
以后可以使用 from_raw_parts_mut
重建指针。
如果指针为空,则返回 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如果指针为空,则返回 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计算与指针的偏移量。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度总和 (以字节为单位) 必须适合于 usize。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_offset
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
基本用法:
let mut s = [1, 2, 3];
let ptr: *mut u32 = s.as_mut_ptr();
unsafe {
println!("{}", *ptr.offset(1));
println!("{}", *ptr.offset(2));
}
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))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 offset
相比,此方法从根本上延迟了留在同一分配对象内的需求: offset
是跨越对象边界时的立即未定义行为; wrapping_offset
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
offset
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
基本用法:
// 使用裸指针以两个元素为增量进行迭代
let mut data = [1u8, 2, 3, 4, 5];
let mut ptr: *mut u8 = data.as_mut_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_offset(6);
while ptr != end_rounded_up {
unsafe {
*ptr = 0;
}
ptr = ptr.wrapping_offset(step);
}
assert_eq!(&data, &[0, 2, 0, 4, 0]);
Run如果指针为 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如果指针为 null,则返回 None
,否则返回 Some
中包装的值的唯一引用。
与 as_mut
相比,这不需要将该值初始化。
有关共享副本,请参见 as_uninit_ref
。
Safety
调用此方法时,您必须确保要么指针是空的,要么以下所有内容都为 true:
-
指针必须正确对齐。
-
在 模块的文档 中定义的含义上,它必须是 “dereferenceable”。
-
您必须执行 Rust 的别名规则,因为返回的生命周期
'a
是任意选择的,不一定反映数据的实际生命周期。特别是,在此生命周期的持续时间内,指针所指向的内存一定不能通过任何其他指针进行访问 (读取或写入)。
即使未使用此方法的结果也是如此!
返回两个指针是否保证相等。
在运行时,此函数的行为类似于 self == other
。
但是,在某些情况下 (例如,编译时评估),并非总是可以确定两个指针是否相等,因此此函数可能会虚假地返回 false
来表示后来实际上相等的指针。
但是,当它返回 true
时,保证指针是相等的。
该函数是 guaranteed_ne
的镜像,但不是其反函数。有两个指针返回 false
的指针比较。
返回值可能会根据编译器版本而改变,并且不安全的代码可能不依赖于这个函数的结果来保证稳健性。
建议仅将此函数用于性能优化,在这种情况下,此函数的虚假 false
返回值不会影响结果,而只会影响性能。
尚未探讨使用此方法使运行时和编译时代码表现不同的后果。
不应使用这种方法来引入这种差异,并且在我们对这个问题有更好的理解之前,也不应使其稳定。
返回两个指针是否保证不相等。
在运行时,此函数的行为类似于 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
的某个值内的两个指针将始终满足最后两个条件。
标准库通常还确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不超过 isize::MAX
字节,因此 ptr_into_vec.offset_from(vec.as_ptr())
始终满足最后两个条件。
从根本上说,大多数平台甚至都无法构建如此大的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
(请注意,offset
和 add
也具有类似的限制,因此也不能在如此大的分配上使用。)
Panics
如果 T
是零大小类型 (“ZST”),则此函数 panics。
Examples
基本用法:
let mut a = [0; 5];
let ptr1: *mut i32 = &mut a[1];
let ptr2: *mut i32 = &mut a[3];
unsafe {
assert_eq!(ptr2.offset_from(ptr1), 2);
assert_eq!(ptr1.offset_from(ptr2), -2);
assert_eq!(ptr1.offset(2), ptr2);
assert_eq!(ptr2.offset(-2), ptr1);
}
Run不正确 用法:
let ptr1 = Box::into_raw(Box::new(0u8));
let ptr2 = Box::into_raw(Box::new(1u8));
let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize);
// 将 ptr2_other 设置为 ptr2 的 "alias",但从 ptr1 派生。
let ptr2_other = (ptr1 as *mut u8).wrapping_offset(diff);
assert_eq!(ptr2 as usize, ptr2_other as usize);
// 由于 ptr2_other 和 ptr2 是从指向不同对象的指针派生的,因此即使它们指向相同的地址,计算其偏移量也是未定义的行为!
unsafe {
let zero = ptr2_other.offset_from(ptr2); // 未定义的行为
}
Run计算与指针的偏移量 (.offset(count as isize)
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量 (以字节为单位) 不会使
isize
溢出。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合
usize
。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_add
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
基本用法:
let s: &str = "123";
let ptr: *const u8 = s.as_ptr();
unsafe {
println!("{}", *ptr.add(1) as char);
println!("{}", *ptr.add(2) as char);
}
Run计算与指针的偏移量 (.offset((count as isize).wrapping_neg())
的便利性)。
count
以 T 为单位; 例如,count
为 3 表示 3 * size_of::<T>()
字节的指针偏移量。
Safety
如果违反以下任一条件,则结果为未定义行为:
-
起始指针和结果指针都必须在边界内或在同一个 分配对象 的末尾之后一个字节。
-
计算的偏移量不能超过
isize::MAX
个 字节。 -
偏移量不能依赖 “wrapping around” 地址空间。也就是说,无限精度的总和必须符合使用大小。
编译器和标准库通常会尝试确保分配永远不会达到需要考虑偏移量的大小。
例如,Vec
和 Box
确保它们分配的字节数永远不会超过 isize::MAX
字节,因此 vec.as_ptr().add(vec.len()).sub(vec.len())
始终是安全的。
从根本上说,大多数平台甚至都无法构造这样的分配。
例如,由于页表的限制或地址空间的分割,没有已知的 64 位平台可以满足 2 63 字节的请求。
但是,某些 32 位和 16 位平台可能通过物理地址扩展之类的东西成功地为超过 isize::MAX
字节的请求提供服务。
因此,直接从分配器获取的内存或内存映射文件 可能 太大而无法使用此函数进行处理。
如果这些约束难以满足,请考虑使用 wrapping_sub
。
此方法的唯一优点是,它可以实现更积极的编译器优化。
Examples
基本用法:
let s: &str = "123";
unsafe {
let end: *const u8 = s.as_ptr().add(3);
println!("{}", *end.sub(1) as char);
println!("{}", *end.sub(2) as char);
}
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))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 add
相比,此方法从根本上延迟了留在同一分配对象内的需求: add
是跨越对象边界时的立即未定义行为; wrapping_add
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
add
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
基本用法:
// 使用裸指针以两个元素为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let step = 2;
let end_rounded_up = ptr.wrapping_add(6);
// 此循环打印 "1, 3, 5, "
while ptr != end_rounded_up {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_add(step);
}
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))
不会使 z
与 y
相同: z
仍附加到对象 x
所附加的对象,并且解引用它是 Undefined Behavior,除非 x
和 y
指向同一分配的对象。
与 sub
相比,此方法从根本上延迟了留在同一分配对象内的需求: sub
是跨越对象边界时的立即未定义行为; wrapping_sub
产生一个指针,但如果指针超出其附加对象的范围而被解引用,则仍会导致未定义行为。
sub
可以更好地优化,因此在性能敏感的代码中更可取。
延迟检查仅考虑解引用的指针的值,而不考虑最终结果计算期间使用的中间值。
例如,x.wrapping_add(o).wrapping_sub(o)
始终与 x
相同。换句话说,允许离开已分配的对象,然后在以后重新输入它。
Examples
基本用法:
// 使用裸指针以两个元素 (backwards) 为增量进行迭代
let data = [1u8, 2, 3, 4, 5];
let mut ptr: *const u8 = data.as_ptr();
let start_rounded_down = ptr.wrapping_sub(2);
ptr = ptr.wrapping_add(4);
let step = 2;
// 此循环打印 "5, 3, 1, "
while ptr != start_rounded_down {
unsafe {
print!("{}, ", *ptr);
}
ptr = ptr.wrapping_sub(step);
}
Run将指针值设置为 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
。
将 count * size_of<T>
字节从 self
复制到 dest
。
源和目标可能 不 重叠。
NOTE: 这与 ptr::copy_nonoverlapping
具有相同的参数顺序。
有关安全性问题和示例,请参见 ptr::copy_nonoverlapping
。
pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
将 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
。
用 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` 对齐,但它会指向分配之外
}
Runpub unsafe fn get_unchecked<I>(
self,
index: I
) -> *const <I as SliceIndex<[T]>>::Output where
I: SliceIndex<[T]>,
pub unsafe fn get_unchecked<I>(
self,
index: I
) -> *const <I as SliceIndex<[T]>>::Output where
I: SliceIndex<[T]>,
如果指针为空,则返回 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
。
pub unsafe fn get_unchecked_mut<I>(
self,
index: I
) -> *mut <I as SliceIndex<[T]>>::Output where
I: SliceIndex<[T]>,
pub unsafe fn get_unchecked_mut<I>(
self,
index: I
) -> *mut <I as SliceIndex<[T]>>::Output where
I: SliceIndex<[T]>,
如果指针为空,则返回 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
。
如果指针为空,则返回 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
是任意选择的,不一定反映数据的实际生命周期。 特别是,在此生命周期的持续时间内,指针所指向的内存一定不能通过任何其他指针进行访问 (读取或写入)。
即使未使用此方法的结果也是如此!