1.60.0
稳定版rustc
中已稳定支持基于LLVM
的覆盖率检测.可用-Cinstrument-coverage
重构代码
,如:
RUSTFLAGS="-C instrument-coverage" cargo build
之后,运行
生成的二进制文件
,它在当前目录
中生成一个default.profraw
文件.环境变量
可覆盖路径和文件名
;有关细节,见文档.
llvm-tools-preview
组件包括llvm-profdata
,来处理和合并
原始配置文件输出
(覆盖区域执行计数);及用llvm-cov
来生成报告.
llvm-cov
结合了llvm-profdata
与二进制
的输出
,因为二进制
文件嵌入了从计数器
到实际源码区域
的映射.
rustup component add llvm-tools-preview
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -sparse default.profraw -o default.profdata
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-cov show -Xdemangler=rustfilt target/debug/coverage-testing \
-instr-profile=default.profdata \
-show-line-counts-or-regions \
-show-instantiations
在简单的helloworld
二进制文件上,执行上述命令
会生成此带注释
的报告,显示已覆盖
每一行输入.
1| 1|fn main() {
2| 1| println!("Hello, world!");
3| 1|}
细节见rustc
书中的文档.
因此,确保llvm-tools-preview
和编译代码的rustc
使用相同
版本.
cargo --timings
Cargo
已稳定了对使用--timings
标志收集
构建信息的支持.
$ cargo build --timings
Compiling hello-world v0.1.0 (hello-world)
Timing report saved to target/cargo-timings/cargo-timing-20220318T174818Z.html
Finished dev [unoptimized + debuginfo] target(s) in 0.98s
Cargo
功能的新语法名字空间
依赖和弱依赖
.
Cargo
长期以来一直支持带可选功能
的依赖项
,如下面代码片所示.
[dependencies]
jpeg-decoder = { version = "0.1.20", default-features = false, optional = true }
[features]
# 并行处理,启用"rayon"特征
parallel = ["jpeg-decoder/rayon"]
此例中,有两点要注意:
1,可选的jpeg-decoder
依赖项隐式
定义了同名
的功能.启用jpeg-decoder
功能依赖启用jpeg-decoder
项.
2,"jpeg-decoder/rayon"
语法启用jpeg-decoder
依赖项,并启用jpeg-decoder
依赖项的rayon
特征.
名字空间
功能解决了第一个问题.现在,可在[features]
表中无需隐式公开
,使用dep:
前缀来显式引用
可选依赖项.
这样可更好
控制如何定义
与可选
依赖项对应的功能
,包括在更具描述性
的功能名
后面隐藏
依赖可选项.
弱依赖
功能解决了第二个问题,即"optional-dependency/feature-name"
语法会总是启用可选依赖
.但是,一般,仅当其他某些功能已启用
可选依赖项时,才想在可选依赖项
上启用该功能.
从1.60
开始,你可像"package-name?/feature-name"
一样,添加一个?
,只有在其他
功能已启用了可选依赖项
时,才会启用给定功能
.
如,假设在库中支持了一些序化
,且需要在一些可选依赖项
中启用
相应的功能.可这样:
[dependencies]
serde = { version = "1.0.133", optional = true }
rgb = { version = "0.8.25", optional = true }
[features]
serde = ["dep:serde", "rgb?/serde"]
此例中,启用serde
功能,依赖启用serde
项.它还依赖为rgb
项启用serde
功能,但前提是其他内容
启用了rgb
依赖项.
API
Arc::new_cyclic
Rc::new_cyclic
slice::EscapeAscii
<[u8]>::escape_ascii
u8::escape_ascii
Vec::spare_capacity_mut
MaybeUninit::assume_init_drop
MaybeUninit::assume_init_read
i8::abs_diff
i16::abs_diff
i32::abs_diff
i64::abs_diff
i128::abs_diff
isize::abs_diff
u8::abs_diff
u16::abs_diff
u32::abs_diff
u64::abs_diff
u128::abs_diff
usize::abs_diff
Display for io::ErrorKind
From<u8> for ExitCode
Not for ! (the "never" type)
_Op_Assign<$t> for Wrapping<$t>
arch::is_aarch64_feature_detected!
1.61.0
稳定版一开始,Rust
主函数只能(隐式或显式
)返回单元类型()
,总是在退出状态
下指示成功,如果想要其他,则必须调用process::exit(code)
.
从Rust1.26
开始,允许main
返回Result
,其中Ok
转换为C
的EXIT_SUCCESS
,Err
转换为EXIT_FAILURE
(也调试打印
错误).在后台,由终止
特征统一这些替代返回类型
.
此版本中,最终用包装
了相关平台的返回类型
的更通用的ExitCode
类型,稳定了终止特征
.它有SUCCESS
和FAILURE
常量,且还为更多任意值
实现了From
.
可为你自己
的类型实现终止特征
,允许在转换为ExitCode
前自定义
报告类型.
如,下面是为git bisect run
脚本编写退出码
类型的安全方法
:
use std::process::{ExitCode, Termination};
#[repr(u8)]
pub enum GitBisectResult {
Good = 0,
Bad = 1,
Skip = 125,
Abort = 255,
}
impl Termination for GitBisectResult {
fn report(self) -> ExitCode {
//也许在此打印一条消息
ExitCode::from(self as u8)
}
}
fn main() -> GitBisectResult {
std::panic::catch_unwind(|| {
todo!("test the commit")
}).unwrap_or(GitBisectResult::Abort)
}
const fn
的更多功能此版本中稳定
了几个渐进特征
,以在常
函数中启用更多功能
:
1,fn
指针的基本处理
:现在可在const fn
中创建,传递和转换
函数指针.如,这对解释器
构建编译时函数表
可能很有用.但是,仍禁止调用fn
指针.
2,特征
边界:在泛型参数
上,现在可把如T:Copy
的特征边界
写入const fn
,以前只允许Sized
.
3,dyn Trait
类型:类似,const fn
现在可处理特征
对象dyn Trait
.
4,impl Trait
类型:const fn
的参数和返回值
现在可以是不透明的impl Trait
类型.
注意,在const fn
中,特征功能尚不支持,从这些特征
调用方法.
更多
stdio
的静态句柄三个标准I/O
流(Stdin,Stdout
和Stderr
)都有一个lock(&self)
,来更好
控制同步读写
.然而,他们返回带从&self
借用生命期
的锁警卫
,因此仅限于原始句柄
的域.
这是不必要
的限制,因为底层
锁实际在静态
存储中,因此现在与句柄
断开连接时,返回带"静态生命期
"的警卫
.
如,常见错误是,试取
句柄并在语句
中锁定
它:
//`error[E0716]`:借用时,丢弃了临时值
let out = std::io::stdout().lock();
//^^^^^^^^^^^^^^^^^在此语句末尾释放`临时值`,创建仍在使用时释放了的临时.
现在锁警卫
是静态
的,而不是临时
借来的,所以这有效
!
API
Pin::static_mut
Pin::static_ref
Vec::retain_mut
VecDeque::retain_mut
Write for Cursor<[u8; N]>
std::os::unix::net::SocketAddr::from_pathname
std::process::ExitCode
std::process::Termination
std::thread::JoinHandle::is_finished
以下以前稳定的函数现在是常
:
<*const T>::offset and <*mut T>::offset
<*const T>::wrapping_offset and <*mut T>::wrapping_offset
<*const T>::add and <*mut T>::add
<*const T>::sub and <*mut T>::sub
<*const T>::wrapping_add and <*mut T>::wrapping_add
<*const T>::wrapping_sub and <*mut T>::wrapping_sub
<[T]>::as_mut_ptr
<[T]>::as_ptr_range
<[T]>::as_mut_ptr_range
1.62.0
稳定版现在,可用cargo add
,直接从命令行
添加新的依赖项
.支持指定功能和版本
.还可用来修改
现有依赖项.
如:
cargo add log
cargo add serde --features derive
cargo add nom@5
更多.
#[默认]
枚举变体现在,如果指定默认变体
,则可在枚举
上使用#[derive(Default)]
.如,目前,必须手动为此枚举
编写默认实现
:
#[derive(Default)]
enum Maybe<T> {
#[default]
Nothing,
Something(T),
}
目前,只允许标记"单位
"变体(无字段
变体)为#[default]
.细节.
Linux
上更薄,更快的互斥锁以前,由Linux
上的pthreads
库,支持Mutex,Condvar
和RwLock
.pthreads
锁支持比RustAPI
自身更多的功能,包括运行时配置
,且可用于静态保证比Rust
更少的语言.
如,按无法移动的40
个字节实现互斥锁
.这强制标准库在后台
为使用pthreads
的平台的每个新互斥锁分配一个Box
.
现在在Linux
上,Rust
的标准库提供了原始基于futex
实现的锁
,它非常轻量
,不需要额外分配
.
在1.62.0
中,在Linux
上的内部状态中,互斥锁
只需要5个字节
,更多.
x86_64
目标现在,为x86_64
构建无操作系统
的二进制
文件更加容易,如在编写内核
时.x86_64-unknown-none
目标已提升到第2级
,可用rustup
安装.
rustup target add x86_64-unknown-none
rustc --target x86_64-unknown-none my_no_std_program.rs
嵌入式的rust
API
bool::then_some
f32::total_cmp
f64::total_cmp
Stdin::lines
windows::CommandExt::raw_arg
impl<T: Default> Default for AssertUnwindSafe<T>
From<Rc<str>> for Rc<[u8]>
From<Arc<str>> for Arc<[u8]>
FusedIterator for EncodeWide
aarch64
上的RDM
内部函数,这里
1.62.1
稳定版1,编译器修复了涉及impl Trait
返回类型的不健全
的函数强制
.
2,编译器修复了异步 fn
生命期的增量编译错误
.
3,窗口
为同步读写
中的重叠I/O
添加了回退
.
1.63.0
稳定版从1.0
开始,Rust
代码可用std::thread::spawn
启动新线程
,但此函数
要用'static
绑定闭包
.即,即线程
当前必须有传递到闭包
中的参数
的所有权;
不能把借用数据
传递到线程
中.如果(通过join()
),应该在结束函数
时,退出线程
,这不必要,可能需要在Arc
中放置数据等变通
方法.
现在,在1.63.0
中,标准库添加了允许生成从本地栈帧
中借用线程
的域线程
.std::thread::scope
,API
提供,即在返回
前,生成线程
都已退出,从而安全借用
数据的必要保证
.
下面是一例:
let mut a = vec![1, 2, 3];
let mut x = 0;
std::thread::scope(|s| {
s.spawn(|| {
println!("hello from the first scoped thread");
//可在此借用`"a"`.
dbg!(&a);
});
s.spawn(|| {
println!("hello from the second scoped thread");
//甚至可在此可变借用`"x"`,因为没有其他线程使用它.
x += a[0] + a[2];
});
println!("hello from the main thread");
});
//在域后,可再次`修改和访问`变量:
a.push(4);
assert_eq!(x, a.len());
I/O
安全)原始文件描述符/句柄的Rust
所有权以前,(在unix
风格平台上)使用带原始文件描述符
或(在窗口
上)句柄
的平台API
的Rust
代码,一般直接
使用相关平台
的描述符表示(如,c_int
或别名RawFd
).
对与此类原生API
的Rust
绑定,类型系统
无法编码API
是否取得
文件描述符的所有权
(如,close
)还是仅借用
它(如,dup
).
现在,Rust
提供了按#[repr(transparent)]
标记的BorrowedFd
和OwnedFd
等包装器类型,即外部"C"
绑定可直接用它们
来编码
所有权语义.
建议新的API
使用它们,而不是以前的(如RawFd
)类型别名.
const
互斥锁,RwLock,Condvar
现在可在常
环境中调用Condvar::new,Mutex::new
和RwLock::new
函数,这样可避免
使用像lazy_static
等仓库
来创建互斥(Mutex),RwLock
或Condvar
的全局静态值
.
对像fn foo
类函数签名,通过鱼
指定T
的具体类型
是错误的:foo::
将失败,并显示:
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> src/lib.rs:4:11
|
4 | foo::<u32>(3, 3);
| ^^^ explicit generic argument not allowed
|
= note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
在1.63
中,放宽
了此限制,且可指定泛型
的显式类型
.但是,impl Trait
参数尽管是泛型,但仍是不透明
的,无法通过鱼
指定.
API
array::from_fn
Box::into_pin
BinaryHeap::try_reserve
BinaryHeap::try_reserve_exact
OsString::try_reserve
OsString::try_reserve_exact
PathBuf::try_reserve
PathBuf::try_reserve_exact
Path::try_exists
Ref::filter_map
RefMut::filter_map
NonNull::<[T]>::len
ToOwned::clone_into
Ipv6Addr::to_ipv4_mapped
unix::io::AsFd
unix::io::BorrowedFd<'fd>
unix::io::OwnedFd
windows::io::AsHandle
windows::io::BorrowedHandle<'handle>
windows::io::OwnedHandle
windows::io::HandleOrInvalid
windows::io::HandleOrNull
windows::io::InvalidHandleError
windows::io::NullHandleError
windows::io::AsSocket
windows::io::BorrowedSocket<'handle>
windows::io::OwnedSocket
thread::scope
thread::Scope
thread::ScopedJoinHandle
这些API
现在可在常
环境中使用:
array::from_ref
slice::from_ref
intrinsics::copy
intrinsics::copy_nonoverlapping
<*const T>::copy_to
<*const T>::copy_to_nonoverlapping
<*mut T>::copy_to
<*mut T>::copy_to_nonoverlapping
<*mut T>::copy_from
<*mut T>::copy_from_nonoverlapping
str::from_utf8
Utf8Error::error_len
Utf8Error::valid_up_to
Condvar::new
Mutex::new
RwLock::new
1.64.0
稳定版IntoFuture
增强.await
Rust1.64
稳定了,类似IntoIterator
的特征,但不是支持for
循环,而是改变.await
的工作方式的IntoFuture
特性.
使用IntoFuture
,.await
关键字不仅可等待未来
;还可等待可通过IntoFuture
转换为Future
的任意东西,帮助API
更加用户友好!
如,构造通过网络请求
某个存储提供者
的构建器
:
pub struct Error { ... }
pub struct StorageResponse { ... }:
pub struct StorageRequest(bool);
impl StorageRequest {
///创建`"StorageRequest"`的新实例.
pub fn new() -> Self { ... }
///决定是否应启用调试模式.
pub fn set_debug(self, b: bool) -> Self { ... }
///发送请求并接收响应.
pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}
典型
用法可能如下:
let response = StorageRequest::new() //`1`.创建新实例
.set_debug(true)//`2`.设置一些选项
.send() //`3`.构建未来
.await?; //`4`.运行未来+传播错误
这还不错,但在此
还可更好.使用IntoFuture
,可把构建"未来"(第3行)和"运行未来"(第4行)
合并为一个步骤
:
let response = StorageRequest::new() //`1`.创建新实例
.set_debug(true) //`2`设置一些选项
.await?;//`3`.构造+运行未来+传播错误
为此,可为StorageRequest
实现IntoFuture
.IntoFuture
要求有个可创建"盒子<未来>
"并为其定义一个类型别名
来完成的可返回的命名未来
:
//首先,必须导入一些新类型到域中.
use std::pin::Pin;
use std::future::{Future, IntoFuture};
pub struct Error { ... }
pub struct StorageResponse { ... }
pub struct StorageRequest(bool);
impl StorageRequest {
///创建`"StorageRequest"`的新实例.
pub fn new() -> Self { ... }
///决定是否应启用调试模式.
pub fn set_debug(self, b: bool) -> Self { ... }
///发送请求并接收响应.
pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}
//新的实现:`1`.创建新的`命名未来`类型
//`2`.为`"StorageRequest"`实现`"IntoFuture"`
pub type StorageRequestFuture = Pin<Box<dyn Future<Output = Result<StorageResponse, Error>> + Send + 'static>>
impl IntoFuture for StorageRequest {
type IntoFuture = StorageRequestFuture;
type Output = <StorageRequestFuture as Future>::Output;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.send())
}
}
更多实现代码
,但给用户
提供了更简单
的API
.
未来,Rust
异步工作组想通过在类型(type)别名
(类型别名实现特征或TAIT
)中支持impl Trait
来简化
创建新的命名未来
.
通过简化类型别名的签名
,来简化实现IntoFuture
的过程,并从类型别名
中删除Box
来提高
性能.
FFI
类型调用或被CABI
调用时,Rust
代码可无需相关目标
的代码或条件
,用(如c_uint
或c_ulong
)类型别名来匹配目标上C的相应类型
.
以前,仅在std
中可用分类名
,因此为嵌入目标和其他
只能使用core
或alloc
的场景,编写的代码
不能用类型别名
.
Rust1.64
现在提供了core::ffi
中的所有c_*
类型别名,及处理C串
的core::ffi::CStr
.Rust1.64
还提供了alloc::ffi::CString
,来仅使用alloc
仓库而不是完整的std
库来处理拥有的C串
.
rustup
取得rust-analyzer
rust-analyzer
这里,现在包含在Rust
附带的工具集合中.这样更容易下载和访问rust-analyzer
,并在多平台
上可用.可作为rustup
组件使用,如下安装:
rustup component add rust-analyzer
此时,要运行rustup
安装的版本,这样调用它:
rustup run stable rust-analyzer
rustup
的下个版本提供内置代理
,以便运行可执行的rust-analyzer
会启动适当
版本.
发布,vsc插件
Cargo
:工作区继承和多目标构建现在,在一个Cargo
工作区中,使用相关库
或二进制仓库
的集合时,可避免在仓库
之间重复通用字段值
,如通用版本号
,仓库URL
或rust-version
,及从工作区
继承依赖项.
也帮助
在更新
仓库时保持这些值
间同步.
在为多个目标
构建时,现在可传递多个--target
选项给cargo build
,以一次构建
所有这些目标.还可在.cargo/config.toml
中,将build.target
设置为包含
多个目标的数组
,以便默认为多个目标
构建.
API
future::IntoFuture
num::NonZero*::checked_mul
num::NonZero*::checked_pow
num::NonZero*::saturating_mul
num::NonZero*::saturating_pow
num::NonZeroI*::abs
num::NonZeroI*::checked_abs
num::NonZeroI*::overflowing_abs
num::NonZeroI*::saturating_abs
num::NonZeroI*::unsigned_abs
num::NonZeroI*::wrapping_abs
num::NonZeroU*::checked_add
num::NonZeroU*::checked_next_power_of_two
num::NonZeroU*::saturating_add
os::unix::process::CommandExt::process_group
os::windows::fs::FileTypeExt::is_symlink_dir
os::windows::fs::FileTypeExt::is_symlink_file
以前在std::ffi
中是稳定的,但现在在core
和alloc
中也可用:
core::ffi::CStr
core::ffi::FromBytesWithNulError
alloc::ffi::CString
alloc::ffi::FromVecWithNulError
alloc::ffi::IntoStringError
alloc::ffi::NulError
以前在std::os::raw
中是稳定的,但现在在core::ffi
和std::ffi
中也可用:
ffi::c_char
ffi::c_double
ffi::c_float
ffi::c_int
ffi::c_long
ffi::c_longlong
ffi::c_schar
ffi::c_short
ffi::c_uchar
ffi::c_uint
ffi::c_ulong
ffi::c_ulonglong
ffi::c_ushort
已稳定了一些来future
下面低级实现的Poll
的助手
:
future::poll_fn
task::ready!
将来,可能会提供更简单的较少低级细节的,如Poll
和Pin
类API
,但同时,这些助手
使得更加容易编写
此类代码.
现在可在常
环境中使用这些API
:
slice::from_raw_parts
Rust1.64.0
更改了Ipv4Addr,Ipv6Addr,SocketAddrV4
和SocketAddrV6
的内存布局
,使其更加紧凑和内存高效
.
1.65.0
稳定版(GAT)
泛型关联类型现在可在关联
类型上定义生命期,类型和常量泛型
,如下:
trait Foo {
type Bar<'x>;
}
这里有些示例特征,以了解它们的强大:
///可从"Self"中借用的,类似"迭代器"的特征
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
///可通过(如`"Rc"`或`"Arc"`)灵针实现,以便允许在指针类型上泛型
trait PointerFamily {
type Pointer<T>: Deref<Target = T>;
fn new<T>(value: T) -> Self::Pointer<T>;
}
///允许借用`项目数组`.适合类似`'NdArray'`的不必连续`存储`数据的类型.
trait BorrowArray<T> {
type Array<'x, const N: usize> where Self: 'x;
fn borrow_array<'a, const N: usize>(&'a self) -> Self::Array<'a, N>;
}
let-else
语句引入了一个新的,带可反驳
的模式和发散的不匹配模式
时执行的else
块的let
型语句.
let PATTERN: TYPE = EXPRESSION else {
DIVERGING_CODE;
};
普通let
语句只能使用无可反驳
模式,即静态
已知总是匹配
.该模式一般只是单个变量绑定
,但也可解包如结构,元组和数组
等复合类型
.
但是,这不适合如提取枚举
变体的条件匹配
,但现在使用let-else
,可像普通let
一样匹配
及绑定
域内变量的可反驳的模式
,或在(如break,return,panic!
)模式
不匹配时发散
.
fn get_count_item(s: &str) -> (u64, &str) {
let mut it = s.split(' ');
let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
panic!("Can't segment count item pair: '{s}'");
};
let Ok(count) = u64::from_str(count_str) else {
panic!("Can't parse integer: '{count_str}'");
};
(count, item)
}
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
名字绑定
的域,是使其与match
或iflet-else
式不同的主要因素.以前,可通过一些重复
和外部的让
来模拟这些模式:
let (count_str, item) = match (it.next(), it.next()) {
(Some(count_str), Some(item)) => (count_str, item),
_ => panic!("Can't segment count item pair: '{s}'"),
};
let count = if let Ok(count) = u64::from_str(count_str) {
count
} else {
panic!("不能解析整:{count_str}'");
};
现在可按中断(break)目标
标记普通块式
,来提前
终止该块.有点类似goto
语句,但它不是goto
语句,只是从块内
跳到块尾
.
这在循环块
中已是可能
的,你可能会看到总是只执行一次的循环
,只是为了得到有标签
的中断
.
现在有个专门
为此的语言功能
!与循环
一样,标签break
也可包含式值
,让多语句块
有早期的"返回"值
.
let result = 'block: {
do_thing();
if condition_not_met() {
break 'block 1;
}
do_next_thing();
if condition_not_met() {
break 'block 2;
}
do_last_thing();
3
};
Linux
调试信息早在Rust1.51
中,编译器团队在macOS
上添加了对拆分调试信息
的支持,现在在Linux
上也可稳定使用该选项
.
1,-Csplit-debuginfo=unpacked
会将调试信息
拆分为多个.dwo
,DWARF
目标文件.
2,-Csplit-debuginfo=packed
除了输出
二进制文件,还生成一个打包所有调试信息
在一起的.dwp
的DWARF
文件.
3,-Csplit-debuginfo=off
仍是默认
,在目标和最终二进制
文件中的.debug_*ELF
节中包括DWARF
数据.
拆分DWARF
允许链接器避免处理调试信息
(因为它不再在链接
目标文件中),这可加快链接时间
!
对相关平台的默认值,其他目标
现在也接受-Csplit-debuginfo
作为稳定选项
,但其他值
仍不稳定.
API
std::backtrace::Backtrace
Bound::as_ref
std::io::read_to_string
<*const T>::cast_mut
<*mut T>::cast_const
特别注意,Backtrace
,API
允许使用一般恐慌回溯
的相同平台相关
的实现,来随时抓栈回溯
.如,这对向错误类型
添加运行时环境
可能很有用.
这些API
现在可在常
环境中使用:
<*const T>::offset_from
<*mut T>::offset_from
Rust1.65
版本中还有其他更改
,包括:
现在启用了MIR
内联以优化
编译.
调度
构建时,Cargo
现在会排序
等待处理作业的队列
,以提高性能.