全部教程·
Rust语言·
Rust高级编程
[目录]
·
布局
Rust 高级编程
Rust 非安全程序设计
Rust 安全代码
安全与非安全代码对比 安全与非安全代码交互 非安全Rust能做什么 编写非安全代码数据布局
repr(Rust) 类型中的奇行种 可选的数据表达方式所有权
所有权 引用 别名 生命周期 生命周期的局限 省略生命周期 无界生命周期 高阶trait边界 子类型和变性 Drop检查 幽灵数据 分解借用类型转换
类型转换 强制类型转换 点操作符 显式类型转换 变形未初始化内存
未初始化内存 安全方式 Drop标志 非安全方式资源管理
基于所有权的资源管理 构造函数 析构函数 泄露展开
展开 异常安全性 污染并发
并发 竞争 Send和Sync 原子操作实现 Vec
实现 Vec 布局 内存分配 push和pop 回收资源 DeRef 插入和删除 IntoIter RawVec Drain 处理零尺寸类型 最终代码FFI
FFI
Rust 高级编程
Rust 非安全程序设计
Rust 安全代码
安全与非安全代码对比 安全与非安全代码交互 非安全Rust能做什么 编写非安全代码数据布局
repr(Rust) 类型中的奇行种 可选的数据表达方式所有权
所有权 引用 别名 生命周期 生命周期的局限 省略生命周期 无界生命周期 高阶trait边界 子类型和变性 Drop检查 幽灵数据 分解借用类型转换
类型转换 强制类型转换 点操作符 显式类型转换 变形未初始化内存
未初始化内存 安全方式 Drop标志 非安全方式资源管理
基于所有权的资源管理 构造函数 析构函数 泄露展开
展开 异常安全性 污染并发
并发 竞争 Send和Sync 原子操作实现 Vec
实现 Vec 布局 内存分配 push和pop 回收资源 DeRef 插入和删除 IntoIter RawVec Drain 处理零尺寸类型 最终代码FFI
FFIRust 布局
我们先来看看结构体的布局。Vec由三部分组成:一个指向分配空间的指针、空间的大小、以及已经初始化的元素的数量。
简单来说,我们的设计只要这样:
pub struct Vec<T> {
ptr: *mut T,
cap: usize,
len: usize,
}
这段代码可以通过编译。可不幸的是,它是不正确的。首先,编译器产生的变性过于严格。所以&Vev<&'static str>不能当做&Vev<&'a str>使用。更主要的是,它会给drop检查器传递错误的所有权信息,因为编译器会保守地假设我们不拥有任何的值。
.正如我们在所有权一章见到的,当裸指针指向一块我们拥有所有权的位置,我们应该使用Unique<T>代替*mut T。尽管Unique是不稳定的,我们尽可能不去使用它。
复习一下,Unique封装了一个裸指针,并且声明它自己:
- 对
T可变 - 拥有类型T的值(用于drop检查)
- 如果
T是Send/Sync,那就也是Send/Sync - 指针永远不为null(所以`Option<Vec>可以做空指针优化)
除了最后一点,其余的我们都可以用稳定的Rust实现:
use std::marker::PhantomData;
use std::ops::Deref;
use std::mem;
struct Unique<T> {
ptr: *const T, // 使用*const保证变性
_marker: PhantomData<T>, // 用于drop检查
}
// 设置Send和Sync是安全地,因为我们是Unique中的数据的所有者
// Unique<t>好像就是T一样
unsafe impl<T: Send> Send for Unique<T> {}
unsafe impl<T: Sync> Sync for Unique<T> {}
impl<T> Unique<T> {
pub fn new(ptr: *mut T) -> Self {
Unique { ptr: ptr, _marker: PhantomData }
}
pub fn as_ptr(&self) -> *mut T {
self.ptr as *mut T
}
}
可是,声明数据不为0的方法是不稳定的,而且短期内都不太可能会稳定下来。所以我们还是接受现实,使用标准库的Unique:
#![feature(ptr_internals)]
use std::ptr::{Unique, self};
pub struct Vec<T> {
ptr: Unique<T>,
cap: usize,
len: usize,
}
如果你不太在意空指针优化,那么你可以使用稳定代码。但是我们之后的代码会依赖于这个优化去设计。还要注意,调用Unique::new是非安全的,因为给它传递null属于未定义行为。我们的稳定Unique就不需要让new是非安全的,因为它没有对于它的内容做其他的保证。
下一章:Rust 内存分配
使用Unique会给Vec(以及所有的标准库集合)带来一个问题:空的Vec不会分配内存。如果既不能分配内存,又不能给ptr传递一个空指针,那我们在Vec::new中能做什么呢?好吧,我们就胡乱往Vec里塞点东西。这么做没 ...
AI 中文社