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);
    }
}

putao
8 声望3 粉丝

推动世界向前发展,改善民生。