Rust 1.27发布

Rust开发团队很高兴地宣布发布Rust的新版本:1.27.0。 Rust是一种针对安全性,速度和并行代码执行的系统编程语言。


如果您使用rustup安装了Rust的早期版本,那么只需将Rust升级到1.27.0版本,您只需执行以下操作:


$ rustup update stable 

如果尚未安装rustup,则可以从我们网站的相应页面进行安装 。 可以在GitHub上找到Rust 1.27.0的详细发行说明


我们还希望引起您的注意:在1.27.0版发布之前,我们发现1.26.0版引入的match映射中存在错误 ,这可能导致不正确的行为。 由于发现的时间很晚,因此虽然已经发布了该版本,但是从1.26.0版本开始就已经存在,因此我们决定不中断该例程并准备一个固定的版本1.27.1,该版本将在不久的将来发布。 另外,如有必要,版本1.26.3。 可以在相应的发行说明中找到详细信息。


稳定版1.27.0中包含什么


在本期中,出现了两个期待已久的重大语言改进。 但是首先,对文档进行一点评论:现在,Rust库中的所有书籍都提供搜索功能 ! 例如,您可以在“ Rust Programming Language”一书中找到“ borrow” 。 我们希望这可以使您轻松找到所需的信息。 此外,一本有关rustc的新书也出现了 。 本书说明了如何直接使用rustc ,以及如何获取其他有用的信息,例如所有静态检查的列表。


SIMD


因此,现在重要了:从现在开始,Rust中提供了使用SIMD基本功能 ! SIMD的意思是“一条指令,多个数据流”(一条指令,多个数据)。 考虑以下功能:


 pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { for ((a, b), c) in a.iter().zip(b).zip(c) { *c = *a + *b; } } 

这里我们取两个整数切片,将它们的元素求和,然后将结果放在第三个切片中。 上面的代码演示了最简单的方法:您需要遍历整个元素集,将它们放在一起并保存结果。 但是,编译器通常会找到更好的解决方案。 LLVM通常会“自动向量化”相似的代码,其中这种复杂的措辞只是意味着“使用SIMD”。 想象一下,切片ab都长16个元素。 每个元素都是u8 ,这意味着切片将每个包含128位数据。 使用SIMD,我们可以将切片ab放入128位寄存器中,并用一条指令将它们相加,然后将得到的128位复制到c 。 它将更快地工作!


尽管Rust的稳定版本始终能够利用自动矢量化功能,但有时编译器不够智能,无法理解可以在这种情况下使用它。 此外,并非所有CPU都支持这些功能。 因此,LLVM不能始终使用它们,因为您的程序可以在多种硬件平台上运行。 因此,在Rust 1.27中,通过添加std::arch模块,可以直接使用这些类型的指令,也就是说,现在我们不必仅依靠智能编译。 此外,我们有机会根据各种标准选择特定的实现。 例如:


 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))] fn foo() { #[cfg(target_arch = "x86")] use std::arch::x86::_mm256_add_epi64; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::_mm256_add_epi64; unsafe { _mm256_add_epi64(...); } } 

在这里,我们使用cfg标志根据目标平台选择正确的代码版本:在x86上将使用其自己的版本,在x86_64上将使用其自己的版本。 我们还可以在运行时选择:


 fn foo() { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { if is_x86_feature_detected!("avx2") { return unsafe { foo_avx2() }; } } foo_fallback(); } 

这里我们有两个版本的函数:一个使用AVX2一种特定的SIMD,允许您执行256位操作。 宏is_x86_feature_detected! 将生成一个代码,检查处理器是否支持AVX2,如果支持,则将调用函数foo_avx2 。 如果没有,我们将求助于没有AVX的实现foo_fallback 。 因此,我们的代码在支持AVX2的处理器上可以非常快速地运行,但是在其他处理器上也可以运行,尽管速度较慢。


一切看起来有点低落且令人不适-是的,是的! std::arch是此类事情的原语 。 我们希望将来我们仍然可以通过高级功能来稳定std::simd 。 但是,基本SIMD功能的出现现在使您可以试验对各种库的高级支持。 例如,签出更快的软件包。 这是没有SIMD的代码段:


 let lots_of_3s = (&[-123.456f32; 128][..]).iter() .map(|v| { 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0 }) .collect::<Vec<f32>>(); 

为了faster在此代码中使用SIMD,您需要像这样进行更改:


 let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter() .simd_map(f32s(0.0), |v| { f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0) }) .scalar_collect(); 

它看起来几乎相同: simd_iter代替itersimd_map代替mapf32s(2.0)代替2.0 。 但是最后,您将获得经过SIMD认证的代码版本。


除此之外,您永远不能自己编写此文件,但是,与往常一样,您依赖的库可以完成此操作。 例如, 已经 regex添加 regex支持 ,其新版本将具有SIMD加速功能,而无需您进行任何操作!


dyn Trait


最后,我们对Rust中最初选择的trait对象的语法感到遗憾。 您还记得,对于Foo ,可以定义如下特征对象:


 Box<Foo> 

但是,如果Foo是结构,则仅意味着将结构放置在Box<T> 。 在开发语言时,我们认为这样的相似性将是一个好主意,但是经验表明这会导致混乱。 它不仅是Box<Trait>impl SomeTrait for SomeOtherTrait也是形式正确的语法,但是您几乎总是需要为impl<T> SomeTrait for T where T: SomeOtherTrait编写impl<T> SomeTrait for T where T: SomeOtherTrait 。 与impl SomeTrait相同,它看起来像向类型添加了方法或可能的默认实现,但实际上,它向类型对象添加了自己的方法。 最后,与最近添加的impl Trait语法相比,该Trait语法看起来更短impl Trait使用,但实际上并非总是如此。


因此,在Rust 1.27中,我们稳定了新的dyn Trait语法。 特性对象现在看起来像这样:


 //  =>  Box<Foo> => Box<dyn Foo> &Foo => &dyn Foo &mut Foo => &mut dyn Foo 

对于其他指针类型也类似: Arc<Foo>现在Arc<Foo> Arc<dyn Foo> ,等等。 由于向后兼容的要求,我们无法删除旧语法,但是我们添加了一个bare-trait-object静态检查,默认情况下会解析旧语法。 如果要禁止它,则可以激活此检查。 我们认为默认情况下启用了检查功能,现在将显示太多警告。


顺便说一下,我们正在开发一个名为rustfix的工具,该工具可以自动将您的代码更新为较新的习惯用法。 他将为此使用类似的静态检查。 敬请关注将来的公告中的rustfix公告。

#[must_use]用于函数


总之,属性#[must_use]得到扩展: 现在可以将其用于函数


以前,它仅适用于类型,例如Result <T, E> 。 但是现在您可以执行以下操作:


 #[must_use] fn double(x: i32) -> i32 { 2 * x } fn main() { double(4); // warning: unused return value of `double` which must be used let _ = double(4); // (no warning) } 

使用此属性,我们还对标准库进行了一些改进 :如果您不使用它们的返回值,则Clone::cloneIterator::collectToOwned::to_owned将发出警告,这将帮助您注意到昂贵的操作,而您的结果被您意外忽略了。


有关更多详细信息,请参见发行说明


图书馆稳定


此版本中稳定了以下新API:



有关更多详细信息,请参见发行说明


货运增强


Cargo在此版本中进行了两项小改进。 首先, --target-dir了一个 --target-dir ,可用于更改目标执行目录。


此外,货运公司关于如何处理目标的方法已经完成。 Cargo尝试检测项目中的测试,示例和可执行文件。 但是,有时需要显式配置。 但是在最初的实施中,这是有问题的。 假设您有两个示例,而Cargo都检测到了两个示例。 您想要配置其中之一,然后将[[example]]添加到Cargo.toml以指定示例参数。 目前,Cargo将看到您已经明确定义了示例,因此不会尝试自动检测其他示例。 这有点不高兴。


因此,我们 'auto'- Cargo.toml 。 我们不能解决这种问题,除非不经意间破坏依赖它的项目。 因此,如果要配置一些目标,而不是全部目标,则可以在[package]部分中将autoexamples键设置为true


有关更多详细信息,请参见发行说明


开发人员1.27.0


很多人参与了Rust 1.27的开发。 没有你们每个人,我们不可能完成工作。


谢谢你


来自翻译:我感谢ruRust社区的成员和ozkriff亲自为他们的翻译和校对提供的帮助

Source: https://habr.com/ru/post/zh-CN415091/


All Articles