diff --git a/src/SUMMARY.md b/src/SUMMARY.md index b7d6dc09..1308c0dc 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -370,3 +370,5 @@ - [1.67](appendix/rust-versions/1.67.md) - [1.68](appendix/rust-versions/1.68.md) - [1.69](appendix/rust-versions/1.69.md) + - [1.70](appendix/rust-versions/1.70.md) + - [1.71](appendix/rust-versions/1.71.md) diff --git a/src/appendix/rust-versions/1.70.md b/src/appendix/rust-versions/1.70.md new file mode 100644 index 00000000..27493366 --- /dev/null +++ b/src/appendix/rust-versions/1.70.md @@ -0,0 +1,81 @@ +# Rust 新版解读 | 1.70 | `OnceCell` && `IsTerminal` + +> Rust 1.70 官方 release doc: [Announcing Rust 1.70.0 | Rust Blog](https://blog.rust-lang.org/2023/06/01/Rust-1.70.0.html) + +通过 [rustup](https://www.rust-lang.org/tools/install) 安装的同学可以使用以下命令升级到 1.70 版本: + +```shell +$ rustup update stable +``` + +## crates.io 默认使用稀疏注册协议 (sparse protocol) + +在 Rust 1.68.0 版本里稳定但需要手动配置来启用的特性,在这个版本中作为默认值了。如今在拉取 crates.io 索引信息时,应该能够观察到大幅性能提升。 + +注意当用户处在有防火墙限制的网络环境下时,需要确保能够访问 `https://index.crates.io` 来使用该协议。如果因为某些原因需要继续使用原先由 Github 托管的 git 索引,可以配置 `registries.crates-io.protocol` 来实现。 + +需要注意,两种访问方式依赖的本地缓存路径是不同的,所以更换访问方式会导致依赖被重新下载。当完全切换到稀疏注册协议后,或许你想要清理存储在 `$CARGO_HOME/registry/*/github.com-*` 的旧依赖项 + + +## `OnceCell` 和 `OnceLock` + +稳定了 `OnceCell` 和多线程安全版本 `OnceLock` 两种共享数据类型,它们都能让数据不需要立刻初始化的同时保证仅初始化一次。 + +```rust +use std::sync::OnceLock; + +static WINNER: OnceLock<&str> = OnceLock::new(); + +fn main() { + let winner = std::thread::scope(|s| { + s.spawn(|| WINNER.set("thread")); + + std::thread::yield_now(); // give them a chance... + + WINNER.get_or_init(|| "main") + }); + + println!("{winner} wins!"); +} +``` + +在之前需要使用 `lazy_static` 或者 `once_cell` 来实现这种效果,如今标准库里从 `once_cell` 的 `unsync` 和 `sync` 模块吸收了这些基础组件。未来可能还会有更多方法被稳定下来,比如存储初始化函数的 `LazyCell` 和 `LazyLock` 类型。不过当前这第一步应该能够覆盖许多使用场景了。 + +## `IsTerminal` + +新稳定的 Trait,包含 `is_terminal` 一个方法,判断给定的文件描述符或者句柄是否代表一个终端/TTY。标准化了之前第三方crates如 `atty` `is-terminal` 实现的功能。一个常见的使用场景是,判断程序是通过脚本执行的还是交互模式执行的,以此在交互模式下实现一些诸如彩色输出、完整TUI的功能。 + +```rust +use std::io::{stdout, IsTerminal}; + +fn main() { + let use_color = stdout().is_terminal(); + // if so, add color codes to program output... +} +``` + +## 调试信息级别的文本化 + +之前 `-Cdebuginfo` 编译选项仅支持数字 0,1,2 来表示逐渐增多的 debug 调试信息。(Cargo 默认在dev和test配置里是 2,在release和bench配置里是 0) + +如今这些级别可以被文本代表:"none" (0), "limited" (1), and "full" (2), 还有两个新级别:"line-directives-only" and "line-tables-only" + +之前 Cargo 和 rustc 的文档都把级别 1 叫做 "line-tables-only",但是级别 1 实际上比这种场景包含的调试信息更多。新的 "line-tables-only" 仅保留的文件名和行号信息的最少调试信息量,或许会在未来成为 `-Cdebuginfo=1` 。另外一个 "line-directives-only" 是为 NVPTX 场景准备的,不推荐使用。 + +注意这些文本化的选项还无法在 `Cargo.toml` 里使用,预计会在下一个 1.71版本里实现。 + + +## Others + +其它更新细节,和稳定的API列表,参考[原Blog](https://blog.rust-lang.org/2023/06/01/Rust-1.70.0.html#stabilized-apis) + +注:可以看到常用的 `Option` `Result` 新增了一些方法: + +* `Option::is_some_and` + * `pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool` +* `Result::is_ok_and` + * `pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool` +* `Result::is_err_and` + * `pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool` + +平时使用时可以试试。 \ No newline at end of file diff --git a/src/appendix/rust-versions/1.71.md b/src/appendix/rust-versions/1.71.md new file mode 100644 index 00000000..11a93067 --- /dev/null +++ b/src/appendix/rust-versions/1.71.md @@ -0,0 +1,76 @@ +# Rust 新版解读 | 1.71 | C-unwind API + +> Rust 1.71 官方 release doc: [Announcing Rust 1.71.0 | Rust Blog](https://blog.rust-lang.org/2023/07/13/Rust-1.71.0.html) + +通过 [rustup](https://www.rust-lang.org/tools/install) 安装的同学可以使用以下命令升级到 1.71 版本: + +```shell +$ rustup update stable +``` + +## C-unwind API + +1.71.0 稳定了 `C-unwind` 和其他 `-unwind` 后缀的ABI,具体见[列表](https://github.com/rust-lang/rust/issues/74990#issuecomment-1363473645) + +非强制unwinding的结果在这个RFC的[表格](https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#abi-boundaries-and-unforced-unwinding)里。 + +带有 `-unwind` 后缀的ABI在由于 `panic` 或者 C++ 的异常(exception) 而执行 unwinding 时,穿过 ABI 边界会更安全,除此以外和没有 `-unwind` 后缀的 ABI 基本等效。使用 `panic=unwind` 可以有效地让异常从一种语言堆栈展开(stack unwind)到另一种语言而不需要中止进程(只要这个异常的产生和捕获都是在同一种语言内进行的)。而 `panic=abort` 通常会立刻中止进程。 + +这次稳定不会影响已有的ABI(比如 `C`),通过这些ABI的 unwinding 仍然是 UB 未定义行为。未来的 Rust 版本会按照这个RFC来修复这些ABI(通常会在边界处abort)。我们鼓励需要unwind穿过ABI边界的用户使用新的 ABI 来确保未来的兼容性。 + +译者注:或许以下一些概念对理解上面这个更新内容有一些帮助: + +* [FFI](https://doc.rust-lang.org/nomicon/ffi.html) +* [what-is-stack-unwinding](https://stackoverflow.com/questions/2331316/what-is-stack-unwinding) +* [Rust Unwinding](https://doc.rust-lang.org/nomicon/unwinding.html) + +## 调试器可视化属性 + +1.71.0 稳定了新的属性:`#[debug_visualizer(natvis_file = "...")]` 和 `#[debug_visualizer(gdb_script_file = "...")]`。它们允许植入 Nativis 描述和 GDB 脚本到 Rust 库里来改善通过调试器查看这些库数据结构时的输出结果。Rust本身有给标准库打包类似的脚本,如今这个特性让库作者也可以给其用户提供类似的体验了。 + +具体细节查看:[the-debugger_visualizer-attribute](https://doc.rust-lang.org/nightly/reference/attributes/debugger.html#the-debugger_visualizer-attribute) + +## raw-dylib 动态库链接 + +在 Windows 平台上,通过在 `#[link]` 里使用新的选项 `kind="raw-dylib"`,Rust 现在支持使用动态库且编译期不需要依赖这个动态库。 + +这避免了要求用户安装这些库(这在跨平台交叉编译的时候尤为困难),也避免了在crates指明需要链接的库的具体版本。 + +使用新的属性 `#[link_ordinal]`, Rust 也支持通过动态库的符号顺序而不是符号名称来进行符号绑定。 + +## 线程局部常量初始化 + +其实是 1.59 稳定进标准库的功能(没有在更新说明和文档里提过)。[文档](https://doc.rust-lang.org/stable/std/macro.thread_local.html) + +```rust +use std::cell::RefCell; +use std::thread; + +thread_local!(static FOO: RefCell = RefCell::new(1)); + +FOO.with(|f| { + assert_eq!(*f.borrow(), 1); + *f.borrow_mut() = 2; +}); + +// each thread starts out with the initial value of 1 +let t = thread::spawn(move|| { + FOO.with(|f| { + assert_eq!(*f.borrow(), 1); + *f.borrow_mut() = 3; + }); +}); + +// wait for the thread to complete and bail out on panic +t.join().unwrap(); + +// we retain our original value of 2 despite the child thread +FOO.with(|f| { + assert_eq!(*f.borrow(), 2); +}); +``` + +## Others + +其它更新细节,和稳定的API列表,参考[原Blog](https://blog.rust-lang.org/2023/07/13/Rust-1.71.0.html#stabilized-apis) +