Rust 中的指针类型主要包括以下几类:引用、原始指针、智能指针。
瘦指针是一个普通的指针,仅包含内存地址。const T 和 mut T 这类原始指针,以及普通的引用 &T 和 &mut T 都是瘦指针。
//不可变引用(&T):表示指向某个值的引用,该引用不能修改值。
//可变引用(&mut T):表示指向某个值的引用,该引用可以修改值。
let x = 10;
let y = &x; // 不可变引用
//原始指针是一种更低级的指针类型,它无需遵循借用规则,因此需要在 unsafe 块中使用
//不可变原始指针(*const T):
//可变原始指针(*mut T):
let x = 5;
let raw_ptr: *const i32 = &x; // 创建不可变原始指针
胖指针包含的不仅是内存地址,还包含额外的元数据。胖指针主要用于以下两种情况:
- 切片(Slice):
切片是动态大小类型(DST, Dynamically Sized Type),它们的胖指针包含数据指针和长度。 - 特征对象(Trait Object):
特征对象是实现了某个特征的类型的实例,它们的胖指针包含数据指针和指向虚表(vtable)的指针。
fn main() {
let arr = [10, 20, 30, 40, 50];
let slice: &[i32] = &arr;
println!("Slice length: {}", slice.len());
println!("First element in slice: {}", slice[0]);
}
trait MyTrait {
fn display(&self);
}
impl MyTrait for i32 {
fn display(&self) {
println!("Value: {}", self);
}
}
fn main() {
let value: i32 = 42;
let trait_obj: &dyn MyTrait = &value;
trait_obj.display();
}
ptr::copy //将内存从一个位置复制到另一个位置,允许区域重叠。unsafe 操作。
#[test]
fn test01() {
let mut src = vec![1, 2, 3];
let mut dest = [0; 8];
unsafe {
ptr::copy(src.as_ptr(), dest.as_mut_ptr(), src.len());
}
println!("Destination array: {:?}", dest); // [1, 2, 3, 4, 5]
}
ptr::copy_nonoverlapping //通常比 ptr::copy 更高效,但需确保区域不重叠。
ptr::drop_in_place
use std::ptr;
fn main() {
let mut x = Box::new(5);
unsafe {
ptr::drop_in_place(&mut *x);
}
// x 现在无效,因为它已经被 drop
}
ptr::eq
let x = 5;
let y = 5;
let px = &x as *const i32;
let py = &y as *const i32;
let pz = &x as *const i32;
println!("Is px equal to py? {}", ptr::eq(px, py)); // false
println!("Is px equal to pz? {}", ptr::eq(px, pz)); // true
ptr::from_exposed_addr
ptr::from_exposed_addr_mut
ptr::from_mut
use std::ptr;
fn main() {
let mut x = 5;
let ptr_x = ptr::from_mut(&mut x);
unsafe {
*ptr_x = 10;
}
println!("x is now: {}", x); // 10
}
//从一个数据指针和元数据创建一个胖指针。在 Rust 中,胖指针一般用于动态大小类型(DST)如切片和特征对象。值得注意的是,这个函数是 unsafe 的,因此使用它时必须非常谨慎。
ptr::from_raw_parts
//手动构建特征对象的胖指针
use std::ptr;
trait MyTrait {
fn display(&self);
}
impl MyTrait for i32 {
fn display(&self) {
println!("Value: {}", self);
}
}
fn main() {
let value: i32 = 42;
let data_ptr: *const () = &value as *const i32 as *const ();
let meta = std::ptr::metadata(std::ptr::null::<dyn MyTrait>());
// 使用 from_raw_parts 创建特征对象胖指针
let trait_obj_ptr: *const dyn MyTrait = unsafe { ptr::from_raw_parts(data_ptr, meta) };
let trait_obj: &dyn MyTrait = unsafe { &*trait_obj_ptr };
trait_obj.display();
}
//手动切片对象的胖指针
use std::ptr;
fn main() {
let arr = [10, 20, 30, 40, 50];
let data_ptr = arr.as_ptr();
let len = arr.len();
// 使用 from_raw_parts 创建胖指针
let slice_ptr: *const [i32] = unsafe { ptr::from_raw_parts(data_ptr, len) };
let slice: &[i32] = unsafe { &*slice_ptr };
println!("Manual Slice length: {}", slice.len());
println!("Manual First element in slice: {}", slice[0]);
}
ptr::from_raw_parts_mut
ptr::from_ref//它在需要将引用转换为原始指针进行某些底层操作时非常有用。
extern "C" {
fn some_c_function(ptr: *const i32);
}
use std::ptr;
fn main() {
let value = 42;
let reference = &value;
// 将引用转换为原始指针并传递给 C 函数
unsafe {
some_c_function(ptr::from_ref(reference));
}
}
ptr::hash
//在实现自定义数据结构时,可能需要对内部数据进行哈希操作,其中涉及到指针的哈希
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::ptr;
struct MyStruct {
data: i32,
}
impl MyStruct {
fn new(data: i32) -> Self {
Self { data }
}
fn hash(&self) -> u64 {
let mut hasher = DefaultHasher::new();
ptr::hash(&self.data as *const i32, &mut hasher);
hasher.finish()
}
}
fn main() {
let my_obj = MyStruct::new(42);
let hash_value = my_obj.hash();
println!("Hash value of my_obj: {}", hash_value);
}
ptr::invalid
ptr::invalid_mut
// 仅为说明用途,实际内核这样写会有更好的方法,不推荐直接使用
const INVALID_ADDRESS: usize = 0xDEADBEEF;
let invalid_ptr: *const u8 = std::ptr::invalid(INVALID_ADDRESS);
ptr::metadata //ptr::metadata 用于获取指针的元数据。
use std::ptr;
fn main() {
let x: i32 = 42;
let x_ptr: *const i32 = &x;
let metadata = ptr::metadata(x_ptr);
println!("{:?}", metadata); // 输出: ()
}
fn main() {
let slice: &[i32] = &[1, 2, 3];
let slice_ptr: *const [i32] = slice;
let metadata = ptr::metadata(slice_ptr);
println!("{:?}", metadata); // 输出: 3 (切片的长度)
}
// 对于 Trait 对象的示例
trait MyTrait {
fn hello(&self);
}
impl MyTrait for i32 {
fn hello(&self) {
println!("Hello from i32!");
}
}
fn main() {
let n: &dyn MyTrait = &42;
let n_ptr: *const dyn MyTrait = n;
let metadata = std::ptr::metadata(n_ptr);
println!("{:?}", metadata); // 输出一些指向虚表的指针信息
}
ptr::null
ptr::null_mut
use std::ptr;
fn main() {
// 假设我们有一个可能返回 null pointer 的外部函数
extern "C" {
fn some_external_function() -> *const i32;
}
unsafe {
let result = some_external_function();
if result.is_null() {
println!("Received a null pointer from the external function");
} else {
println!("Received a non-null pointer from the external function");
}
}
}
ptr::read//给定指针处读取一个值
ptr::read_unaligned //它不要求指针是对齐的。
ptr::read_volatile //编译器不会对 volatile 操作进行优化
use std::ptr;
fn main() {
let x = 42;
let x_ptr = &x as *const i32;
unsafe {
let value = ptr::read(x_ptr);
println!("{}", value); // 输出: 42
}
}
ptr::replace//用于将指针所指向位置的值替换为一个新的值,并返回旧值
use std::ptr;
fn main() {
let mut x = 42;
let mut y = 13;
let x_ptr: *mut i32 = &mut x;
let y_ptr: *mut i32 = &mut y;
unsafe {
let old_x = ptr::replace(x_ptr, 99);
println!("Old x: {}", old_x); // 输出: Old x: 42
println!("New x: {}", x); // 输出: New x: 99
let old_y = ptr::replace(y_ptr, 88);
println!("Old y: {}", old_y); // 输出: Old y: 13
println!("New y: {}", y); // 输出: New y: 88
}
}
use std::ptr;
fn main() {
let mut x = 42;
let x_ptr: *mut i32 = &mut x;
unsafe {
let old_x = ptr::replace(x_ptr, 99);
println!("Old x: {}", old_x); // 输出: Old x: 42
println!("New x: {}", x); // 输出: New x: 99
}
}
ptr::slice_from_raw_parts //创建一个不可变的切片,引用从给定原始指针开始的一段内存。
ptr::slice_from_raw_parts_mut
use std::ptr;
fn main() {
let arr = [1, 2, 3, 4, 5];
let ptr = arr.as_ptr();
let slice: &[i32] = unsafe {
ptr::slice_from_raw_parts(ptr, 3)
};
println!("{:?}", slice); // 输出: [1, 2, 3]
}
ptr::swap
ptr::swap_nonoverlapping
use std::ptr;
fn main() {
let mut x = [1, 2, 3, 4];
let mut y = [5, 6, 7, 8];
// 获取 x 和 y 数组的指针
let px: *mut i32 = x.as_mut_ptr();
let py: *mut i32 = y.as_mut_ptr();
// 交换 px 和 py 指向的数组内容
unsafe {
ptr::swap_nonoverlapping(px, py, x.len());
}
println!("x: {:?}", x); // 输出:x: [5, 6, 7, 8]
println!("y: {:?}", y); // 输出:y: [1, 2, 3, 4]
}
ptr::write//主要用于需要初始化或更新内存区域的场景,例如在低级系统编程中。
use std::ptr;
#[derive(Debug)]
struct MyStruct {
a: i32,
b: f64,
}
fn main() {
let mut s = MyStruct { a: 0, b: 0.0 };
let ptr: *mut MyStruct = &mut s;
unsafe {
// 写入新值到结构体
ptr::write(ptr, MyStruct { a: 42, b: 3.14 });
// 输出写入后的结构体
println!("MyStruct after write: {:?}", *ptr);
}
}
ptr::write_bytes// 主要用于初始化大块连续内存区域,例如清零或填充内存区域。
use std::ptr;
fn main() {
let mut buf = [0u8; 20];
let ptr: *mut u8 = buf.as_mut_ptr();
unsafe {
// 设置内存区域的所有字节为 0xAA
ptr::write_bytes(ptr, 0xAA, buf.len());
// 输出初始化后的数组
println!("Buffer after write_bytes: {:?}", buf);
}
}
//用于向内存中写入数据,且不要求目标内存地址必须是对齐的(aligned)。它特别有用在处理某些数据结构或嵌入式系统编程等场景,
ptr::write_unaligned
use std::ptr;
fn main() {
let mut buf: [u8; 5] = [0; 5];
let ptr: *mut u32 = buf[1..].as_mut_ptr() as *mut u32; // 故意使其未对齐
unsafe {
// 使用 write_unaligned 将新值写入到未对齐的内存位置
ptr::write_unaligned(ptr, 0xAABBCCDD);
// 打印 buf 数组以验证写入的值
println!("Buffer: {:?}", buf);
}
}
ptr::write_volatile //用于执行易失(volatile)内存写操作。
use std::ptr;
fn main() {
const GPIO_BASE: *mut u32 = 0x2000_0000 as *mut u32; // 假设 GPIO 基址
unsafe {
// 向 GPIO 寄存器写值,确保不会被优化掉
ptr::write_volatile(GPIO_BASE, 0x1);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。