指针
1/19/26About 3 min
指针
对指针的理解
指针是一个变量,它存储了另一个变量的内存地址。通过指针,我们可以在内存上快速的找到我们要访问的数据。
Tips
在这里我们借用 LLDB 调试,来直观的观察数据在内存上的表现形式,这有助于帮助我们理解这些数据储存的底层逻辑。
关于如何使用 LLDB 调试 rust,我们可以参考 LLDB 调试 这篇文章。
先来一个简单的例子
let a = 0;
let b = &a;
println!("a:{}, b:{}", a, b);这里我们定义了一个 int 类型的变量 a,它的值为 0。而 b 引用了 a 的内存地址,所以 b 指向了 a 的内存地址,我们可以通过 b 来访问 a 的值。这里我们可以说 b 是一个指向 a 的指针。
在 LLDB bug 模式中,我们可以通过 p 命令来打印 a 和 b 的值。
$ p a
(int) 0
$ p b
(int *) 0x000000016fdfd534在上边的代码中,我们可以看到 a 是一个 int 类型的变量,它的值为 0。而 b 是一个 int * 类型的指针,通过 b 可以访问到 a 的值。
我们可以通过 memory read 命令来查看 b 指向的内存地址上的值。
$ memory read 0x000000016fdfd504 --count 1
0x16fdfd504: 00在 rust 中,我们可以通过 * 来解引用指针,从而访问到指针指向的内存地址上的值。
let a = 0;
let b = &a;
println!("a:{}, b:{}", a, *b); // a:1 b:1我们来看看rust在中声明一个Vec类型它在内存上的表现形式。
let a = vec![1, 2, 3];想要查看 a 的指针,我们可以通过 p &a 来打印
$ p &a
(alloc::vec::Vec<int, alloc::alloc::Global> *) 0x000000016fdfd518
## 观察a的引用地址和类型,这里不同的执行环境可能地址不一样,但是类型是一样的
## 这里我们知道a是一个int类型的Vec
$ memory read 0x000000016fdfd518
0x16fdfd518: 03 00 00 00 00 00 00 00 50 44 f0 42 01 00 00 00
0x16fdfd528: 03 00 00 00 00 00 00 00 18 d5 df 6f 01 00 00 00
## 这里是一个胖指针,前8字节是数字的长度,后8字节是指向的内存地址。下面的是其他数据的内存视图,忽略
## 格式: len(03 00 00 00 00 00 00 00) pointer(50 44 f0 42 01 00 00 00)
## 很明显这里采用了小端序,既数组的长度是3,指针指向的内存地址是0x0000000142f04450
$ memory read 0x0000000142f04450
0x142f04450: 01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00
0x142f04460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
## 根据上面的内存视图,我们可以分析出,a指向的内存地址上存储了3个int类型的数字
## 分别是 int(01 00 00 00) int(02 00 00 00) int(03 00 00 00)RefCell的工作原理
我们知道RefCell是一个运行时检查的借用检查器,它可以在运行时检查是否违反了借用规则。
问题:它是如何维护 borrow / borrow_mut 之间的关系的?