1.38.0
流水编译
要编译仓库
,编译器不需要完全
构建依赖项
.相反,只需要它们的"元数据
"(即类型,依赖关系,导出列表
).
在编译过程的早期生成此元数据
.从Rust1.38.0
开始,Cargo
利用这一点,在准备好元数据
后立即
自动开始构建依赖的仓库
.
检查错误使用mem::{uninitialized, zeroed}
尚未弃用mem::uninitialized;
.但是,从1.38.0
开始,rustc
使用mem::uninitialized
或mem::zeroed
检查一小类错误
初化.
对某些(如&T
和Box<T>
)类型,包含全0
位模式是未定义行为
.
因此,使用mem::uninitialized
或mem::zeroed
初化这些类型
之一是错误的,使用
其中一个函数
初化时,无论是直接
还是按较大结构成员
初化,新检查器
都会发出警告.
检查
是递归
的,因此以下
代码发出警告:
struct Wrap<T>(T);
struct Outer(Wrap<Wrap<Wrap<Box<i32>>>>);
struct CannotBeZero {outer: Outer,foo: i32,bar: f32
}
...
let bad_value: CannotBeZero = unsafe { std::mem::uninitialized() };
Rust
有更多不能为零的类型,特别是NonNull<T>
和NonZero<T>
.目前,不检查
使用mem::uninitialized
或mem::zeroed
初化这些结构
.
检查
并不涵盖所有不合理使用mem::uninitialized
或mem::zeroed
的情况,只是帮助识别
绝对错误的代码.仍应移动
所有代码以改用MaybeUninit
.
#[deprecated]
宏
现在可用弃用宏
来弃用
宏
std::any::type_name
对调试
,取类型名
有时很有用.如,在泛型
代码中,想在运行时
查看函数
的已实例化
类型参数的具体类型
.现在可用std::any::type_name
完成此操作:
fn gen_value<T: Default>() -> T {println!("初化了实例{}", std::any::type_name::<T>());Default::default()
}
fn main() {let _: i32 = gen_value();let _: String = gen_value();
}
这打印:
初化`i32`的实例
初化`alloc::string::String`的实例
更改库
1,现在除了&T
之外,slice::{concat,connect,join}
还接受&[T]
.
2,*const T
和*mut T
现在实现了marker::Unpin
.
3,Arc<[T]>
和Rc<[T]>
现在实现了FromIterator<T>
.
4,iter::{StepBy,Peekable,Take}
现在实现了DoubleEndedIterator
.
此外,已稳定下来这些功能
:
1,<*const T>::cast
和<*mut T>::cast
2,持续时间(Duration)::as_secs_f32
和持续时间::as_secs_f64
3,持续时间::div_f32
和持续时间::div_f64
4,持续时间::from_secs_f32
和持续时间::from_secs_f64
5,持续时间::mul_f32
和持续时间::mul_f64
6,余数和除法
运算,对所有整数原语
的div_euclid,rem_euclid
.还提供检查,溢出和包装
版本.
1.39.0
稳定版
.await
结束了,async fn
在此
在Rust1.39.0
中,很高兴地宣布async/.await
已稳定!即,可定义异步函数和块
,并.await
它们.
可通过编写async fn
而不是fn
来引入异步函数
,只是调用时返回Future
.该Future
是个暂停计算
,可通过.await
它来完成它.此外,
async fn
async { ... }
async move { ... }
可定义异步字面.
另见这里.
对匹配警卫中按移动
绑定的引用
在Rust
中匹配模式
时,可如下绑定
变量:
1,按引用
,可是不变
,也可是可变
的.可显式,如通过ref my_var
或ref mutmy_var
.不过,一般,可自动推导绑定模式
.
2,按值或按复制
(绑定变量
类型实现Copy
时)或按移动
.
以前在匹配式
的if
守卫中,Rust
会禁止按移动
绑定共享引用
.即会拒绝以下代码
:
fn main() {let array: Box<[u8; 4]> = Box::new([1, 2, 3, 4]);match array {nums
//`----'nums'`按移动绑定if nums.iter().sum::<u8>() == 10
//`------'.iter()'`隐式取`'nums'`引用.=> {drop(nums);
//`-----------'nums'`按移动绑定,所以有所有权.}_ => unreachable!(),}
}
在Rust1.39.0
中,编译器现在接受
了上面的代码片.
函数参数的属性
在Rust1.39.0
中,现在允许在函数,闭包和函数指针
的参数上添加属性
.在此之前,可能已写过:
#[cfg(windows)]
fn len(slice: &[u16]) -> usize {slice.len()
}
#[cfg(not(windows))]
fn len(slice: &[u8]) -> usize {slice.len()
}
…你现在可更简洁地写:
fn len(#[cfg(windows)] slice: &[u16], //在`Windows`上使用此参数.在其他地方,使用下面.#[cfg(not(windows))] slice: &[u8], //
) -> usize {slice.len()
}
可在此位置使用的属性
包括:
1,条件编译:cfg
和cfg_attr
2,控制检查
:允许,警告,拒绝和禁止
3,应用
至项的过程宏属性
使用的助手属性
.
借用检查器(略).
标准库中的更多常量函数
在Rust1.39.0
中,以下函数变成了const fn
:
1,Vec::new,String::new
和LinkedList::new
2,str::len,[T]::len
和str::as_bytes
3,ABS,wrapping_abs
和overflowing_abs
标准库的新增内容
以下函数
已稳定下来:
1,Pin::into_inner
2,Instant::checked_duration_since
和Instant::saturating_duration_since
1.40.0
稳定版
#[non_exhaustive]
结构,枚举和变体
附加
到结构或枚举
变体时,#[non_exhaustive]
属性,阻止
定义它的仓库
外部的代码
,构造所述结构或变体
.为了避免未来破坏
,其他仓库
也无法在字段
上完全匹配.
以下示例说明了beta
中依赖于alpha
的错误:
//`alpha/lib.rs:`
#[non_exhaustive]
struct Foo {pub a: bool,
}
enum Bar {#[non_exhaustive]Variant { b: u8 }
}
fn make_foo() -> Foo { ... }
fn make_bar() -> Bar { ... }//beta/lib.rs:
let x = Foo { a: true }; //~ 错误
let Foo { a } = make_foo(); //~ 错误// 添加更多字段,`beta`仍编译
let Foo { a, .. } = make_foo(); //~ OKlet x = Bar::Variant { b: 42 }; //~ 错误
let Bar::Variant { b } = make_bar(); //~ 错误
let Bar::Variant { b, .. } = make_bar(); //~ 好
//仍编译.
背后是,对#[non_exhaustive]
版的结构或枚举变体
,构造器
的可见性被降级到pub(crate)
,从而阻止
在定义它的仓库
之外访问它.
#[non_exhaustive]
的一个更重要
方面是它也可附加
到枚举
自身.如标准库中取的Ordering
:
#[non_exhaustive]
pub enum Ordering { Relaxed, Release, Acquire, AcqRel, SeqCst }
这里,#[non_exhaustive]
确保未来可添加
更多变体.编译器拒绝:
match ordering {//如果添加了新的变体,这是个错误,这在编译器升级时会突然中断.Relaxed | Release | Acquire | AcqRel | SeqCst => {/*逻辑*/}
}
而,其他
仓库需要用如_
添加通配符分支
来考虑更多变体
:
match ordering {Relaxed | Release | Acquire | AcqRel | SeqCst => { /*`...`*/ }//好;如果添加更多变体,就不会破坏._ => { /*逻辑*/ }
}
改进宏和属性
包括:
1,在类型环境中,调用mac!()
过程宏.
如,你可编写:
type Foo = expand_to_type!(bar);
//expand_to_type是过程宏.
2,extern{...}
块中的宏.
包括bang!()
宏,如:
macro_rules! make_item { ($name:ident) => { fn $name(); } }
extern {make_item!(alpha);make_item!(beta);
}
3,现在还支持extern{...}
块中项的过程宏属性
:
extern "C" {//假设扩展为`'fn foo();'`.#[my_identity_macro]fn foo();
}
4,产生macro_rules!
过程宏中的项.
类似(mac!())
的函数和(#[mac])
属性宏,现在都可生成macro_rules!
项目.
5,$m:meta
匹配器支持任意令牌流值
.
即,以下内容
现在有效
:
macro_rules! accept_meta { ($m:meta) => {} }
accept_meta!( my::path );
accept_meta!( my::path = "lit" );
accept_meta!( my::path ( a b c ) );
accept_meta!( my::path [ a b c ] );
accept_meta!( my::path { a b c } );
标准库中的更多常量函数
在Rust1.40.0
中,以下函数变成了const fn
:
1,正整数
版的is_power_of_two
.
标准库的新增内容
在Rust1.40.0
中,稳定了以下函数和宏
:
1,todo!()
unimplemented!()
的更短,更可读,更方便
的版本.
2,slice::重复(repeat)
通过n
次重复切片
来创建Vec<T>
.
3,mem::take
此函数
从可变引用
中取值,并用类型
默认值替换
它.类似Option::take
和Cell::take
,并为mem::replace(&mut dst,Default::default())
提供了一个方便的简写.
4,BTreeMap::get_key_value
和HashMap::get_key_value
返回与提供的键
对应的键值对
.
5,可选(Option)::as_deref
,可选::as_deref_mut
类似Option::as_ref
和Option::as_mut
,但也分别使用Deref
和DerefMut
,因此opt_box.as_deref()
和opt_box.as_deref_mut()
,其中opt_box:Option<Box<T>>
分别生成Option<&T>
和Option<&mut;T>
.
6,可选::flatten
此函数把Option<Option<T>>
变平为Option<T>
,对Some(Some(x))
变平为Some(x)
,否则为None
.该函数类似Iterator::flatten
.
7,UdpSocket::peer_addr
返回此套接字
连接到的远端
的套接字地址
.
8,{f32,f64}::to_be_bytes,{f32,f64}::to_le_bytes,{f32,f64}::to_ne_bytes,{f32,f64}::from_be_bytes,{f32,f64}::from_le_bytes
和{f32,f64}::from_ne_bytes
按big-endian(network),little-endian
和native-endian
字节序排列,并按字节数组
返回浮点数的内存表示
.
1.41.0
稳定版
放宽实现特征
的限制
在Rust1.41.0
之前,孤儿规则
过于严格,妨碍
了组合.如,假设你的仓库
定义了BetterVec<T>
结构,且想要转换结构
为标准库的Vec<T>
.
要写的代码是:
impl<T> From<BetterVec<T>> for Vec<T> {//`...`
}
是如下模式
的一个实例:
impl<T> ForeignTrait<LocalType> for ForeignType<T> {//`...`
}
在Rust1.40.0
中,孤立规则
会禁止该impl
,因为From
和Vec
都是在标准库
中定义的,这与当前的仓库
无关.
有些方法如新类型模式
,可绕过这些限制
,但它们一般很麻烦
.
虽然From
和Vec
仍是外部
的,但特征(本例为From
)是由局部类型
参数化的.因此,Rust1.41.0
允许该实现.
过时时,cargo install
更新安装包
从Rust1.41.0
开始,如果自安装
以来发布了新版本,cargo install
也会更新
现有安装的仓库
版本.此版之前,必须传递即使二进制仓库
是最新的,也会重装的--force
标志.
不易冲突的Cargo.lock
格式
Rust1.41.0
为文件引入了新的格式
在FFI
中使用Box<T>
时的更多保证
从Rust1.41.0
开始,声明T:Sized
的Box<T>
现在与C语言
的(T*)
指针类型兼容.
因此,如果有从C调用的extern"C"
的Rust
函数,你的Rust
函数现在对特定T
,可指定Box<T>
,同时对相应
函数,用C语言中的T*
.
如,在C端,可能有:
//C头文件,返回所有权给调用者.
struct Foo* foo_new(void);
//从调用者取所有权;使用`NULL`调用时为`空操作`.
void foo_delete(struct Foo*);
而在Rust
方面,你:
#[repr(C)]
pub struct Foo;
#[no_mangle]
pub extern "C" fn foo_new() -> Box<Foo> {Box::new(Foo)
}
//用`"Option<_>"`表示`NULL`的可能性.
#[no_mangle]
pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
但注意,虽然Box<T>
和T*
有相同的表示和ABI
,但Box<T>
仍必须为非空
,对齐
且准备好由全局分配器
释放.为此,最好只使用全局
分配器的Box
.
更改库
在Rust1.41.0
中,标准库补充
:
1,Result::map_or
和Result::map_or_else
方法已稳定.
2,与Option::map_or
和Option::map_or_else
类似,
.map(|val| process(val)).unwrap_or(default)
是上面的快捷方式.
3,(如果是较小
整数宽度)NonZero*
数值现在实现From<NonZero*>
.如,NonZeroU16
现在实现From<NonZeroU8>
.
4,弱针上的weak_count
和strong_count
方法已稳定.
std::rc::Weak::weak_count
std::rc::Weak::strong_count
std::sync::Weak::weak_count
std::sync::Weak::strong_count
这些方法分别返回分配的弱(rc::Weak<T>
和sync::Weak<T>
)或强(Rc<T>
和Arc<T>
)指针数.
MaybeUninit<T>
现在实现了fmt::Debug
.
在Rust1.41.0
中,因为静态值
内部表示有些变化,借用检查器
意外地允许
了一些不健全的程序.即,借用检查器不会检查
静态项是否有正确类型
.
这反之又允许分配生命期小于"静态"
的临时变量
给静态变量:
static mut MY_STATIC: &'static u8 = &0;
fn main() {let my_temporary = 42;unsafe {//在`1.41.0`中错误地允许了:MY_STATIC = &my_temporary;}
}
此问题已在1.41.1
中得到解决.
在复制
实现中遵守"静态生命期
"
从Rust1.0
开始,一直编译
以下错误程序:
#[derive(Clone)]
struct Foo<'a>(&'a u32);
impl Copy for Foo<'static> {}
fn main() {let temporary = 2;let foo = (Foo(&temporary),);drop(foo.0); //必须访问`"foo"`的一部分.drop(foo.0); //也可以`索引数组`.
}
在Rust1.41.1
中,已修复此问题.
错误原因是对某些'a
,Foo<'a>
仅在'a:'static
时实现Copy
.但是,带'0
生命期的临时变量
不会超过'static'
存活,因此Foo<'0>
不是Copy
,因此第二次使用drop
应该是个错误.
1.42.0
稳定版
选项
和结果
恐慌消息中的有用行号
unwrap_err,expect,及expect_err和相应Result类型
函数,
所有这八个
函数都会生成带行号的恐慌
消息.新的错误消息如下
:
`"main"`线程,在`"None"`值上"调用`'Option::unwrap()'`时恐慌`',src/main.rs:2:5`
即在src/main.rs
的第2行无效调用
了unwrap
.
子切片模式
允许在切片
上匹配.像这样:
fn foo(words: &[&str]) {match words {[] => println!("empty slice!"),[one] => println!("one element: {:?}", one),[one, two] => println!("two elements: {:?} {:?}", one, two),_ => println!("多少元素?"),}
}
虽允许在切片
上匹配,但相当有限
.必须选择想支持的确切
尺寸,且要加分支
.
在Rust1.42
中,扩展支持切片
的部分匹配
,这里:
fn foo(words: &[&str]) {match words {["Hello", "World", "!", ..] => println!("Hello World!"),["Foo", "Bar", ..] => println!("Baz"),rest => println!("{:?}", rest),}
}
因为与切片
的其余部分匹配,..
叫"其余模式".上例在切片
末尾使用其余
模式,但也可按其他方式
用它:
fn foo(words: &[&str]) {match words {//最后元素必须是`"!"`,忽略其他元素.[.., "!"] => println!("!!!"),//最后元素必须是`"z"`,`"start"`是除最后元素之外的`所有元素`的切片.[start @ .., "z"] => println!("starts with: {:?}", start),//第一个元素必须是`"a"`,`"end"`是除第一个元素之外的`所有元素`的切片.["a", end @ ..] => println!("ends with: {:?}", end),rest => println!("{:?}", rest),}
}
更多
matches!
稳定了一个新的matches!
宏.此宏接受式及模式
,如果模式与式
匹配,则返回true
.即:
//使用匹配式:
match self.partial_cmp(other) {Some(Less) => true,_ => false,
}
//使用`'matches!'`宏:
matches!(self.partial_cmp(other), Some(Less))
还可用|
模式和if
防护:
let foo = 'f';
assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));
let bar = Some(4);
assert!(matches!(bar, Some(x) if x > 2));
现在可使用proc_macro::TokenStream;
在Rust2018
中,删除了extern crate
的需求.但是过程宏
有点特殊,要写过程宏时,仍需要
extern crate proc_macro;
此版本中,如果使用Cargo
,则在使用2018
版时不再需要此行
;可像使用
其他仓库一样使用.
库
1,iter::Empty<T>
现在对T
实现发送和同步
.
2,Pin::{map_unchecked,map_unchecked_mut}
不再需要返回类型
实现Sized
.
3,io::Cursor
现在实现了PartialEq
和Eq
.
4,Layout::new
现在是const
.
稳定的API
1,CondVar::wait_while
和CondVar::wait_timeout_while
2,DebugMap::key
和DebugMap::value
3,ManuallyDrop::take
4,PTR::slice_from_raw_parts_mut
和PTR::slice_from_raw_parts