Rust小版本更新1.96.0:三个痛点一次解决,范围能复制、断言会说话、网页链接不装瞎
Rust 1.96.0稳定了新范围类型、断言匹配宏,修复WebAssembly链接漏洞和Cargo安全漏洞,提升代码可复制性和错误诊断体验。
我们搞定了Rust 1.96.0的几个麻烦事
写代码就像收拾房间,你总希望有些东西能随手拿来就用,而不是翻箱倒柜。这次Rust更新主要解决了几个日常扎心的小问题。先给个痛快话:现在你可以把数字范围直接塞进一个能复制的结构体里了,检查函数返回值是不是符合某种格式也有了更友好的报错方式,另外给网页程序(WebAssembly)链接时不再偷偷摸摸放过错误。下面咱们就掰扯掰扯这些变化到底是怎么让你少掉几根头发的。
新出的范围类型终于能放心复制了
以前你用0..5这种范围表达式,它自己就是个迭代器,就像一张正在播放的CD,你没法直接复制它,因为你复制的是“正在播放的状态”还是“CD里的歌单”?这很让人头大。比如你想写一个结构体来记住要切取字符串的哪一段,老办法得分别记下开始和结束位置,麻烦得像出门前检查自己带没带钥匙、手机、钱包。
现在标准库里多了一组新的范围类型,比如core::range::Range。它们不直接当迭代器用,而是能乖乖被复制。这就好比你把一张歌单(而不是正在播放的CD)印在纸上,想复印几张就几张。
来看个例子。假设你想写一个工具,专门从一句话里切出一段:
rust
use core::range::Range;
#[derive(Clone, Copy)]
pub struct Span(Range);
impl Span {
pub fn of(self, s: &str) -> &str {
&s[self.0]
}
}
这段代码的意思是:我们定义了一个叫Span的结构体,里面只装了一个范围。我们给这个结构体加上Clone和Copy的标签,就像给它贴了个“可复印”的贴纸。然后你给它一个字符串,它就能按照这个范围把对应的一段切出来给你。
以前你想做同样的事,得在结构体里放两个数字(开始和结束),然后每次用的时候都要自己小心别弄错顺序。现在一个范围全搞定,清爽得像夏天喝了口冰水。
不过要记住,你现在写的0..5这种语法,暂时还是老样子(旧的范围类型),要等到未来的某个Rust版本才会自动变成新的。如果你想现在就坚定地用新类型,就明确从core::range里导入。
新出的断言宏让报错信息不再像天书
你写代码时经常要检查某个值是不是符合你的预期,比如“这个随机数应该在1到6之间”。以前你用assert!(matches!(value, 1..=6)),一旦失败,它只告诉你“条件不成立”,就像你问老师为什么这题错了,老师只说“因为错了”一样让人抓狂。
现在有了assert_matches!和debug_assert_matches!这俩新宏。它们做同样的事,但失败时会把你那个实际的值打印出来。比如你期待一个随机数在1到6之间,结果它给你返回了4(没错,就是《xkcd》漫画里那个经典笑话:掷骰子选一个随机数,结果永远是4),如果它返回了7,报错信息就会显示“期待匹配1..=6,实际得到7”。
先得手动把它们拉进你的代码里用:
rust
use core::assert_matches;
/// 参考xkcd漫画221的随机数生成器
fn get_random_number() -> u32 {
// 通过公正的骰子掷出
// 保证完全随机
4
}
fn main() {
assert_matches!(get_random_number(), 1..=6);
}
为啥不自动放进标准预lude(标准库自动导入的那堆东西)里?因为外面有很多流行的第三方库已经自己写了同名的宏,Rust团队不想让大家代码突然冲突,就像你家楼道里不能同时站两个叫“老王”的邻居。
网页程序链接时不再偷偷放过错误
以前给网页程序(WebAssembly)编译链接时,如果有些符号(相当于程序的零件)找不到,链接器会偷偷把它们变成从“环境模块”导入的东西。这就像你组装模型时少了个轮子,结果说明书说“没事,我们假装从邻居家借一个”。这样经常导致程序跑起来才莫名其妙地挂掉。
从Rust 1.96.0开始,链接器不再允许这种行为。如果你少了一个必需的零件,链接阶段就直接报错,像快递发现少发了一个螺丝就拒绝发货一样,逼你当场解决。
如果你想恢复以前那种“从环境借”的行为,有两个办法:
- 编译时加个标志:RUSTFLAGS=-Clink-arg=--allow-undefined
- 或者在源代码里,在定义那个符号的代码块上方加上#[link(wasm_import_module = "env")]
这个改变其实之前就在博客上预告过,现在正式生效了。
技术细节原文照搬
下面这些是更新中涉及的具体命令行、代码和配置路径,直接原样复制:
$ rustup update stable
rustup default beta
rustup default nightly
下面这段是标准的Rust代码示例,用于展示新的Range类型用法:
rust
use core::range::Range;
#[derive(Clone, Copy)]
pub struct Span(Range);
impl Span {
pub fn of(self, s: &str) -> &str {
&s[self.0]
}
}
下面是assert_matches!的使用示例:
rust
use core::assert_matches;
/// Random Number
fn get_random_number() -> u32 {
// chosen by a fair dice roll.
// guaranteed to be random.
4
}
fn main() {
assert_matches!(get_random_number(), 1..=6);
}
如果你想恢复旧的链接行为,可以使用这个环境变量设置:
RUSTFLAGS=-Clink-arg=--allow-undefined
或者在代码中这样标注:
rust
#[link(wasm_import_module = "env")]
这次稳定下来的API列表(新功能接口):
- assert_matches!
- debug_assert_matches!
- From
- From
- From
- core::range::RangeToInclusive
- core::range::RangeToInclusiveIter
- core::range::RangeFrom
- core::range::RangeFromIter
- core::range::Range
- core::range::RangeIter
Cargo(Rust的包管理工具)修复了两个安全漏洞:
- CVE-2026-5223:中等严重程度,跟解压带有符号链接的压缩包有关
- CVE-2026-5222:低严重程度,跟标准化后的网址认证有关
如果你只用官方的crates.io仓库,这两个漏洞都跟你没关系。
更多小变化和感谢
其他所有在Rust、Cargo和Clippy(一个检查工具)里的变化,你可以去官方发布的完整记录里翻翻。这次1.96.0版本是很多人一起搞出来的,没他们可不行,谢谢各位。