#rust - 原文:[https://without.boats/blog/changing-the-rules-of-rust/](https://without.boats/blog/changing-the-rules-of-rust/) - marker traits - 如果一个 API 可以操作某个类型的值,其他一些类型却不行,那么这个 API 必须 bound by marker trait。这样用户就无法传递给它不支持的类型。 # Rules of Rust ## Send - 一些不能跨线程发送的类型: - 类型提供了共享访问,但是它的引用技术不是线程安全的,如`Rc` - 类型包含了无法保证线程安全的 OS API,如 `Args`, `MutexGuard` - 任何可能向另一个线程发送值的 API 都需要指定 `Send` bound,例如 - `thread::spawn`:创建线程。 - `rayon::join`:在一个线程池上运行两个任务。 - `tokio::spawn`:可能会将 task 移动到 executor 的另一个线程。 - 通过 `Send` bound,Rust可以支持不能跨线程发送的类型。 - Alternative:Rust 强制要求所有类型都必须可跨线程发送。 - `Send` trait 是由标准库强制执行的。(用户可以自己实现 libcore,不需要改变 rustc,但代价是无法与其他代码兼容。) ## Move - 假设你希望Rust支持那些一旦地址被观察到就无法使其失效而需要运行析构函数的类型。 > Let’s say you want Rust to support types which can’t be invalidated without running their destructor once their address has been witnessed - 即 immoveable type, 这是 stackless coroutines 和 intrusive data structure 所需要的。 - 为了支持这个,你可能需要引入一个 marker trait 即 `Move`,代表可以自由 move 的类型。 - 不像 `Send`,`Move` 需要一些语法上的支持,最近的方式: - 如果没有实现 Move,获取某个变量的地址时会获取该类型的所有权,阻止其后续被 Move。 - 某些 APIs 需要 bounded by `Move`,来允许 move out of a reference,例如: - `mem::swap`:交换两个 mutable 引用的值 - `mem::replace` :替换 mutable 引用的值 - Rust 并没有实现 `Move` trait,而是使用了 `Pin` 包装指针类型。 - 尽管 `Move` trait 更易用,但是无法做到**向后兼容**。 ## Leak - 假设你希望Rust支持那些在不运行其析构函数的情况下无法超出作用域的类型。 - 这是 linear types 的两个不同定义之一。 - 需要引入一个 marker trait 即 `Leak`,代表了不需要析构也可以超出作用域的类型。 - `Leak`不需要语言层面的支持, > its not possible to “leak” a value in the core language of Rust, you have to use standard library APIs to do it. - 某些需要 bounded by `Leak` 的APIs - 始终 leak 一个 value 的 APIs(`mem::forget`) - 由你来调用析构函数的 APIs (`ManuallyDrop::new`) - 允许 cyclic shared ownership,并且可以意外 leak values(`Rc::new`, `Arc::new`) - Rust 没有 `Leak` trait,但它几乎有。这个讨论在2015年初达到了高潮,当时发现 Rust 正在使用的 scoped thread API 是不安全的,因为其安全性依赖于其保护类型永远不会泄漏。Rust将不支持无法 leak 的类型,因此不会添加 `Leak` trait。