rakulang, dartlang, nimlang, golang, rustlang, lang lang no see

Two Beautiful Rust Programs

焉知非鱼

Two Beautiful Rust Programs

Two Beautiful Rust Programs

这是一则 Rust 编程语言的短广告,目标是有经验的 C++ 开发者。作为一则广告,它只能吊起你的胃口,具体内容请参考其他资源。

第一个程序:

fn main() {
  let mut xs = vec![1, 2, 3];
  let x: &i32 = &xs[0];
  xs.push(92);
  println!("{}", *x);
}

这个程序创建了一个 32 位整数的向量(std::vector<int32_t>),接收第一个元素 x 的引用,再向向量推送一个数字,然后使用 x。这个程序是错误的:扩展向量可能会使对元素的引用无效,而且 *x 可能会取消引用一个 danging 指针。

这个程序的好处是它不会被编译。

error[E0502]: cannot borrow xs as mutable
    because it is also borrowed as immutable
 --> src/main.rs:4:5

     let x: &i32 = &xs[0];
                    -- immutable borrow occurs here
     xs.push(92);
     ^^^^^^^^^^^ mutable borrow occurs here
     println!(x);
              - immutable borrow later used here

Rust 编译器跟踪每块数据的别名状态,并禁止潜在的别名数据的突变。在这个例子中,xxs 别名了向量在堆中存储的第一个整数。

Rust 不允许做傻事。

第二个程序:

use crossbeam::scope;
use parking_lot::{Mutex, MutexGuard};

fn main() {
  let mut counter = Mutex::new(0);

  scope(|s| {
    for _ in 0..10 {
      s.spawn(|_| {
        for _ in 0..10 {
          let mut guard: MutexGuard<i32> = counter.lock();
          *guard += 1;
        }
      });
    }
  }).unwrap();

  let total: &mut i32 = counter.get_mut();
  println!("total = {}", *total)
}

这个程序创建一个由 mutex 保护的整数计数器,生成10个线程,从每个线程开始将计数器递增10次,并打印出总数。

计数器变量位于堆栈中,这些堆栈数据的指针与其他线程共享。线程必须锁定 mutex 才能进行增量。打印总数时,绕过 mutex 读取计数器,没有任何同步。

这个程序的妙处在于,它的正确性依赖于几位精妙的推理,每一个推理都会被编译器检查。

子线程不会逃离主函数 所以可以从它的堆栈中读取计数器

子线程只通过 mutex 访问 counter。

子线程将在我们从计数器中读出总数而不使用 mutex 时终止。

如果这些约束中的任何一个被破坏,编译器就会拒绝该代码。没有必要使用 std::shared_ptr 只是为了防御性地确保内存不会在你的脚下被释放。

Rust 允许做危险的、聪明的、快速的事情,而不用担心引入未定义的行为。

如果你喜欢你所看到的,这里有两本我推荐的书,可以让你更深入地了解 Rust。

原文链接: https://matklad.github.io/2020/07/15/two-beautiful-programs.html