Rust 中的 Pin, Unpin 和 !Unpin

为什么需要 Pin?

引入 Pin 的目的主要是为了支持 自引用类型 (self-referential types) 。下面我们以 Future 为例,解释一下自引用类型以及引入 Pin 的必要性。

由于异步块/异步函数中可能包含对局部变量的引用,例如下面的代码:

理解 Rust 的生命周期 (Lifetime)

Lifetime 的主要目的是防止悬空引用 (dangling references)

下面的例子中, borrow checker 会检查 r 的生命周期 'a 比其引用的数据的生命周期 'b 要长,因此会拒绝编译通过。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// ❌ borrowed value does not live long enough
fn main() {
    let r;                // ---------+-- 'a
                          //          |
    {                     //          |
        let x = 5;        // -+-- 'b  |
        r = &x;           //  |       |
    }                     // -+       |
                          //          |
    println!("r: {}", r); //          |
}                         // ---------+

Lifetime 是一种特殊的泛型参数

具体到形式层面,Lifetime 实际上是一种特殊的泛型参数,这些泛型参数为编译器提供了有关引用之间如何相互联系的信息。

Rust 的 move 和 C++ 的 std::move

Rust 的 move 和 C++ 的 std::move 在表面上看有些相似之处,因为它们都涉及到数据或资源的转移。然而,它们在设计理念、实现方式以及它们在各自语言中所扮演的角色上有着根本的区别。

Rust 中的 Move 语义

所有权转移
Rust 中的 move 语义是其所有权系统的核心部分。当一个值从一个变量移动到另一个变量时,原始变量不再有权访问该值。这避免了悬垂指针和数据竞争等问题。
编译时检查
Rust 的编译器在编译时就会检查所有权、借用和生命周期规则,确保内存安全而无需运行时开销。
自动控制
Rust 的 move 语义是通过编译器自动实现的,不需要程序员提供特殊的代码来支持 move 语义。

C++ 中的 Move 语义

资源转移
C++11 引入了 move 语义,主要用于优化资源管理,减少不必要的对象复制。通过 std::move ,可以将一个对象的状态或资源转移到另一个对象,原对象则处于一个有效但未定义的状态。
标准库的支持
C++ 的 move 语义与其标准库紧密结合,许多容器和算法都对 move 语义进行了优化。
手动控制
与 Rust 的自动和严格的所有权模型不同,C++ 程序员需要更多地手动管理资源和使用 move 语义,这提供了灵活性但也增加了错误的可能性。

具体来讲,C++ 的 move 语义是通过类的『移动构造函数』和『移动赋值运算符』来提供支持的。

发布我的第一个 Crate: django-auth

今天发布了我的第一个 crate: django-auth, 虽然是一个非常简单的 crate, 但麻雀虽小,五脏俱全,API 文档、测试用例、doc test 等一个都不能少 😎。

先简单介绍一下这个库,然后再介绍一下在 crates.io 上发布 crate 的流程。

Rust 中的特征 (Trait)

Trait 初探

trait 是 Rust 中用来定义共享行为的抽象机制,和 Java 的 interface, Swift 的 protocol 等接口抽象机制有点类似。

定义一个 trait 很简单:

1
2
3
trait Callable {
    fn call(&self);
}

为 Rust 的 str 类型实现该 trait (impl​ements Callable for str):