从C++指针和引用理解Rust借用

37 阅读2分钟

C++的指针和引用

指针

指针是一个变量,存储内存地址。可以指向任何地址,也可以为空。

int a = 10;
int* p = &a;  // p存储a的地址

内存布局(32位系统):

地址        变量名    内存内容(十六进制)    说明
0x1000      a        0A 00 00 00           存储值10(小端序)
0x2000      p        00 10 00 00           存储a的地址0x1000

引用

引用是别名,创建时必须绑定到对象,之后不能重新绑定。

int a = 10;
int& r = a;  // r是a的别名

内存布局(实现层面):

地址        变量名    内存内容(十六进制)    说明
0x1000      a        0A 00 00 00           存储值10(小端序)
0x2000      r        00 10 00 00           编译器一般实现为指针,指向0x1000

注:引用在语法层面是别名,实现层面通常是指针

Rust的借用

Rust的借用是通过引用( &T 和 &mut T )来实现的,借用是概念,引用是语法形式。分两种:

不可变借用

let a = 10;
let b = &a;  // b借用a,不能修改a

可变借用

let mut a = 10;
let b = &mut a;  // b可变借用a,可以修改a

关键区别

内存结构相同

指针、引用、借用,在内存中都是地址值。

Rust不可变借用

let a = 10;
let b = &a;
地址        变量名    内存内容(十六进制)    访问类型
0x1000      a        0A 00 00 00           原始值
0x2000      b        00 10 00 00           只读借用

Rust可变借用

let mut a = 10;
let b = &mut a;
地址        变量名    内存内容(十六进制)    访问类型
0x1000      a        0A 00 00 00           可修改
0x2000      b        00 10 00 00           可写借用

规则不同

C++引用:

  • 创建后不能重新绑定
  • 可以悬空(指向已销毁对象)
  • 无借用限制

Rust借用:

  • 有严格借用规则
  • 编译期检查生命周期
  • 防止数据竞争

借用规则

  1. 一个可变借用,或多个不可变借用
  2. 借用不能比原值活得长
  3. 编译期检查所有借用

示例对比

C++可能出问题:

int& get_ref() {
    int x = 10;
    return x;  // 悬空引用
}

Rust编译期阻止:

fn get_ref() -> &i32 {
    let x = 10;
    &x  // 编译错误:借用不能返回
}