Skip to content

Rust 内存布局

借用规则

  1. 任意时刻,只能拥有一个可变引用或任意个不可变引用(可变与不可变不能同时存在)
  2. 引用必须总是有效

借用类型

borrow() 返回 Ref<T> 类型的智能指针;
borrow_mut() 返回 RefMut<T> 类型的智能指针;
两者都实现了 Deref 可作为常规引用。

线程安全类型

Send 允许在线程间传递所有权,Sync 允许多线程访问
如果 &TSend 的话,T 就是 Sync,其引用可以安全地发送到另一个线程

智能指针

Box

使用栈空间需要在编译时知道数据大小,Box 提供在栈空间固定的大小(1 个机器字),指向在堆分配的空间

let t: Box<dyn Vehicle>;
t = Box::new(Truck);

使用 Pin 固定

std::pin - Rust > pin_project - Rust > Pin and suffering

  • Pin<P> 阻止所包装的指针指向的数据被移动
  • PinUnpin 只影响被指向的数据 P::Target

构建一个 Pin<Box<T>> ,如果 T 未实现 Unpin ,那么 x 会被固定在内存中无法移动

pub fn pin(x: T) -> Pin<Box<T, Global>>

Box::pin(x)
// is the same as
Box::into_pin(Box::new(x))

如果 Self 满足 Unpin ,从 Pin<&mut Self> 会隐式转换到 &mut Self

在成员不满足 Unpin 的情况下,从 Pin<&mut Self> 转换到 &mut Self

// 获取不满足 `Unpin` 的成员
let (mut sleep, reader) = unsafe {
    let this = self.get_unchecked_mut();
    (
        Pin::new_unchecked(&mut this.sleep),
        Pin::new_unchecked(&mut this.reader),
    )
}

// 使用 `pin_project`
#[pin_project]
struct SlowRead<R> {
    #[pin]
    reader: R,
    #[pin]
    sleep: Sleep,
}
// 调用 `project` 获取自动生成的结果
let mut this = self.project();

在 receiver 不满足 Unpin 的情况下,创建 Pin,需要确保 pin 之后不再使用 unpin

let mut f = SlowRead::new();
// 创建自身的 `pin`,并 shadow 自身的 `unpin`
let mut f = unsafe { Pin::new_unchecked(&mut f) };
f.read_exact(&mut buf).await?;

// 使用 `pin_utils`
pin_utils::pin_mut!(f);

Rc

允许对同一数据创造多个只读引用,并在最后一个引用离开作用域时释放数据的内存。

Rc 未实现 SendSync,因为多个线程同时访问或修改引用计数会导致数据竞争;可使用 Arc 替代

Cell

RefCell

在运行时检查借用规则,提供内部可变性

impl Messenger for MockMessenger {
    fn send(&self, messenger: &str) {
        self.sent_messenges.borrow_mut().push(String::from(messenger));
    }
}

Trait object

  • trait object 是储存数据指针 (data pointer) 与虚表指针 (vtable pointer) 的胖指针 (fat pointer);
  • data pointer 指向原数据;
  • vtable pointer 指向实现某种 trait 的 vtable,vtable 在编译时生成,共享给相同类型的所有 object;
  • 在进行类型转换时,通过在原指针后添加相应 vtable pointer 形成胖指针。

trait object 是动态大小的类型,必须用引用或其它指针获取

let mut buffer: Vec<u8> = vec![];
let w: &mut dyn Write = &mut buffer;
let mut buffer: Vec<u8> = vec![];
let mut w: Box<dyn Write> = Box::new(buffer);