中文版《Rust标准库》来了

5,891 阅读6分钟
====================================
Rust标准库- 中文版 , 欢迎大家一起来参与 !!
====================================
Rust标准库是可移植Rust软件的基础,Rust软件是针对更广泛的Rust生态系统的一组最小且经过测试的共享抽象. 它提供了诸如 Vec<T> 和 Option<T>之类的核心类型, 对语言原语的库定义操作, 标准宏, I/O 和 多线程, 等等.
Std默认情况下可用于所有Rust库. 因此, 标准库可以在 use 语句 通过 std路径访问, 就像使用use std::env一样

Rust标准库之旅

  1. 容器和集合 option 和 result 模块定义可选和错误处理的类型 : Option<T> 和 Result<T, E>. iter 模块定义Rust的迭代器特质 Iterator, 与for 循环一起使用以访问集合.
标准库公开了三种处理内存连续区域的常用方法:
  • Vec<T> - 在运行时可调整大小的堆分配向量/vector
  • [T; n] - 在编译时具有固定大小的内联数组
  • [T] - 具有容纳动态大小切片的任何类型连续存储, 无论是否进行堆分配
切片只能通过某种指针来处理,因此有多种形式,例如:
  • &[T] - 共享切片
  • &mut [T] - 可变切片
  • Box<[T]> - 拥有切片
str, UTF-8字符串切片是一种原始类型, 标准库为此定义了许多方法. Rust str通常被当作不可变的引用: &str来访问 . 使用拥有/owned String来构造和可变字符串
要转换为字符串,请使用 format! 宏;要从字符串转换,请使用 FromStr 特质.
可以通过将数据放在引用计数的 box 或 Rc 类型中来共享数据, 如果进一步包含在 Cell 或 RefCell,则可以对其进行突变和共享. Likewise, in a concurrent setting it is common to pair an atomically-reference-counted box, Arc, with a Mutex to get the same effect.
该collections 模块定义了 maps , sets , linked lists 和其他典型的集合类型,包括 HashMap<K, V>.
2. 平台抽象和 I/O 除了基本数据类型外,标准库还主要关注常见平台(尤其是Windows和Unix派生)中的差异的抽象
常见类型的 I/O, 包括 files, TCP, UDP, 在被定义在 io, fs, 和 net 模块.
该 thread 模块包含Rust的线程抽象. sync 进一步包含其他原始共享内存类型, 包括 atomic 和 mpsc, 其中包含用于消息传递的通道类型.

模块 std::thread

线程模型

正在执行的Rust程序包含一组原生OS线程,每个原生线程都有自己的堆栈和局部状态。可以命名线程,并为低级同步提供一些内置支持。
线程之间的通信可以通过 channels(通道), Rust的消息传递类型, 以及 其他形式的线程同步 和共享内存数据结构来完成. 特别是,使用原子引用计数的容器类型 Arc, 可 以在线程之间轻松共享并保证线程安全.
Rust中的致命逻辑错误导致线程崩溃,在此期间线程将展开堆栈,运行析构函数并释放拥有的资源. 尽管这并不是一种 'try/catch'机制,但 Rust的恐慌仍然可以通过catch_unwind捕获(除了使用`panic=abort`进行编译 ) 或通过resume_unwind从中恢复. 如果恐慌没有捕获线程将退出,但恐慌可以通过join可选地从其他线程检测到. 如果主线程出现恐慌而没有捕获到,则应用程序将以非零的退出代码退出。
当Rust程序的主线程终止时,即使其他线程仍在运行,整个程序也会关闭。但是,此模块提供了便利的功能,可以自动等待子线程的终止(即 join).

产生线程

可以使用 thread::spawn函数产生一个新线程:
use std::thread;

thread::spawn(move|| {
    // some work here
});
在此示例中,生成的线程是与当前线程 "分离" 的。这意味着它可以在其父线程(产生它的线程)之外存活,除非该父线程是主线程。
父线程也可以等待子线程的完成, 调用spawn产生的 JoinHandle,提供了join等待方法:
use std::thread;

let child = thread::spawn(move|| {
// some work here
});
// some work here

let res = child.join();
该 join 方法返回一个thread::Result 包含子线程Ok产生的最终值的内容,或者子线程panic!时 返回Err 值来调用panic!。

配置线程

可以通过Builder类型在产生新线程之前对其进行配置,当前该类型允许您设置子线程的名称和堆栈大小:
use std::thread;
			
thread::Builder::new().name("child1".to_string()).spawn(move|| {
    println!("Hello, world!");
});

Thread 类型

线程通过 Thread类型表示,您可以通过以下两种方式之一来获取:
  • 通过生成一个新的线程,例如,使用的thread::spawn函数,在 JoinHandle上调用thread.
  • 通过请求当前线程,使用thread::current 函数.
该thread::current函数甚至适用于不是由该模块API产生的线程

线程局部存储

该模块还为Rust程序提供了线程局部存储的实现。线程局部存储是一种将数据存储到全局变量中 的方法,程序中的每个线程都有其自己的副本。线程不共享此数据,因此不需要同步访问。
线程局部键拥有其包含的值,并且在线程退出时将销毁该值。它是使用thread_local!宏创建, 可以包含任何'static(无借入指针)值。它提供了一个访问器函数,该with函 数 产生对指定闭包的值的共享引用。线程局部键仅允许共享访问值,因为如果允许可变借用,则无法保证唯一性。大多数值都希望通过Cell 或 RefCell 类型 利用某种形式的内部可变性.

命名线程

线程能够具有关联的名称以用于识别。默认情况下,生成的线程是未命名的。要为线程指定名称,请使用Builder构建线程, 并将所需的线程名称传递给Builder::name。要从 线程内部检索线程名称,请使用Thread::name。几个使用线程名称的地方的例子:
  • 如果命名线程发生panic,则线程名称将显示在panic消息中
  • 在适用的情况下(例如,在类Unix平台中的pthread_setname_np )将线程名称提供给OS.

堆栈大小

生成线程的默认堆栈大小为2 MiB,尽管此特定堆栈大小将来可能会更改。有两种方法可以手动指定生成的线程的堆栈大小:
  • 使用Builder构建线程,并将所需的堆栈大小传递给Builder::stack_size.
  • 将RUST_MIN_STACK环境变量设置为代表所需堆栈大小(以字节为单位)的整数。请注意,设置Builder::stack_size 将覆盖此设置 .
请注意,主线程的堆栈大小不是由Rust确定的