1 - Rust的指针概述

Rust的指针概述

Rust 中将可以表示内存地址的类型成为 指针

Rust提供了多种类型的指针:

  • 引用(Reference)
  • 原生指针(Raw Pointer)
  • 函数指针(fn Pointer)
  • 智能指针(Smart Pointer)

Rust 可以划分为 Safe Rust 和 Unsafe Rust 两部分。

Safe Rust

引用主要应用于 Safe Rust。

在Safe Rust 中,编译器会对引用进行借用检查,以保证内存安全和类型安全。

Unsafe Rust

原生引用主要用于 Unsafe Rust。

原生引用不在 Safe Rust 的控制范围内,需要编程人员自己保证安全。

2 - Rust的引用(Reference)

Rust的引用(Reference)

Rust 提供引用操作符 &,可以直接获取表达式的存储单元地址,即内存地址。

引用本质上是一种非空指针。

let a = [1,2,3];
let b = &a;
println!("{:p}", b); // 0x7ffcbc067704

// 要获取可变引用,必须先声明可变绑定
let mut c = vec![1,2,3];
// 通过 &mut 得到可变引用
let d = &mut c;
d.push(4);
println!("{:?}", d); // [1, 2, 3, 4]

let e = &42;
assert_eq!(42, *e);

从语义上说,不管是 &a 还是 &mut c,都是对原有变量的所有权的借用,所以引用也被称为借用。

3 - Rust的原始引用(Raw Reference)

Rust的原始引用(Raw Reference)

Rust 支持两种原始引用:

  • 不可变原始指针 *const T
  • 可变原始指针 *&mut T

用 as 操作符可以将引用转为原始指针:

let mut x = 10;
let ptr_x = &mut x as *mut i32;
let y = Box::new(20);
let ptr_y = &*y as *const i32;

// 原生指针操作要放在unsafe中执行
unsafe {
    *ptr_x += *ptr_y;
}
assert_eq!(x, 30);

4 - Rust的函数指针(Fn Pointer)

Rust的函数指针(Fn Pointer)

函数在Rust中是一等公民,函数自身就可以作为函数的参数和返回值使用。

函数作为参数

​```
/// 将函数作为参数传递
pub fn math(op: fn(i32, i32) -> i32, a: i32, b: i32) -> i32{
    /// 通过函数指针调用函数
    op(a, b)
}
fn sum(a: i32, b: i32) -> i32 {
    a + b
}
fn product(a: i32, b: i32) -> i32 {
    a * b
}

let a = 2;
let b = 3;
assert_eq!(math(sum, a, b), 5);
assert_eq!(math(product, a, b), 6);
​```

函数作为返回值

fn is_true() -> bool { true }
/// 函数的返回值是另外一个函数
fn true_maker() -> fn() -> bool { is_true }
/// 通过函数指针调用函数
assert_eq!(true_maker()(), true);
​```

5 - Rust的智能指针(Smart Pointer)

Rust的智能指针(Smart Pointer)

智能指针 (Smart Pointer) 源自c++,Rust 引入后成为 Rust 语言中最重要的一种数据结构。

功能介绍

Rust 中的值默认被分配到 栈内存。可以通过 Box<T> 将值装箱(在堆内存中分配)。

  • Box<T> 是指向类型为T的堆内存分配值的智能指针。
  • Box<T> 超出作用域范围时,将调用其析构函数,销毁内部对象,并自动释放内存。
  • 可以通过解引用操作符来获取Box<T>中的T

Box<T> 的行为像引用,并可以自动释放内存,所以称为智能指针。

Box<T>类型

Rust 中提供了很多智能指针类型。

#[derive(Debug, PartialEq)]
struct Point {
    x: f64,
    y: f64,
}
let box_point = Box::new(Point { x: 0.0, y: 0.0 });
let unboxed_point: Point = *box_point;
assert_eq!(unboxed_point, Point { x: 0.0, y: 0.0 });