avatar Nihil

Nichts Hsu

  • 首页
  • 子域
  • 分类
  • 标签
  • 归档
  • 关于
首页 Rust 2022 年稳定的语法
文章

Rust 2022 年稳定的语法

发表于 2022/12/30
作者 Nichts Hsu
7 分钟阅读
Rust 2022 年稳定的语法
Rust 2022 年稳定的语法

概览

在整个 2022 年,Rust 一共发布了 1.58.0 ~ 1.66.0 共 9 个版本,让我们感谢 Rust 团队一整年的付出。

通常来说,大部分人都不是喜欢追着 Release Note 啃的类型,因此对于大部分人而言,Rust 的语法就只有书上写出来的那一些。这也是我撰写这篇文章的目的:总结和记录 Rust 整个 2022 年稳定的语法,让更多人意识到 “原来 Rust 还支持这种写法!”。

那么,让我们开始吧。

字符串格式化可以捕捉标识符

  • 稳定于:1.58.0

从这个版本开始,Rust 可以在格式化字符串时捕捉上下文中的变量:

1
2
3
4
5
fn main() {
    let s1 = "Hello";
    let s2 = "world";
    println!("{s1} {s2}");
}

不仅如此,上下文变量还可以用作格式化参数(注:由于 HTML 的特性,width 参数引入的空格会被消除,因此点击下方按钮得到的运行结果与实际效果有差别):

1
2
3
4
5
6
fn main() {
    let value = 114.514;
    let width = 10;
    let precision = 1;
    println!("{value:width$.precision$}");
}

内联汇编

  • 稳定于:1.59.0

用官方的例子来展示,下面的代码会将 x 乘以 6:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use std::arch::asm;

fn main() {
    let mut x: u64 = 4;
    unsafe {
        asm!(
            "mov {tmp}, {x}",
            "shl {tmp}, 1",
            "shl {x}, 2",
            "add {x}, {tmp}",
            x = inout(reg) x,
            tmp = out(reg) _,
        );
    }
    println!("x is {x}");
}

解构赋值

  • 稳定于:1.59.0

从这个版本开始,可以在等号左侧使用元组、切片和结构模式进行解构赋值。值得注意的是,let 绑定一直以来都支持解构,这个语法使得赋值和绑定在语法上更加统一:

1
2
3
4
5
6
7
8
9
10
11
12
struct S {
    e: i32,
    f: i32,
}

fn main() {
    let (a, b, c, d, e);
    (a, b) = (1, 2);
    [c, .., d, _] = [1, 2, 3, 4, 5];
    S { e, .. } = S { e: 5, f: 3 };
    println!("{:?}", (a, b, c, d, e));
}

泛型常量优化

  • 稳定于:1.59.0

在此之前,Rust 要求泛型常量参数必须位于泛型参数列表的最后,而在此版本之后不再对此做出要求;另一方面,从这个版本开始,泛型常量参数可以有默认值(只能用于定义 struct, enum, type 和 trait),但是拥有默认值的泛型常量参数仍然需要放在泛型参数列表的最后:

1
2
3
4
5
6
7
8
9
10
11
12
13
#[derive(Debug)]
struct TwoArr<T, const M: usize, U, const N: usize = 10> {
    arr1: [T; M],
    arr2: [U; N],
}

fn main() {
    let two_arr = TwoArr {
        arr1: [1, 2, 3, 4],
        arr2: ["hello", "world"],
    };
    println!("{two_arr:?}");
}

main 函数自定义退出代码

  • 稳定于:1.61.0

最初,main 函数只能返回 (),如果想要异常退出,只能通过 process::exit(code)。

自 Rust 1.26.0 以来,main 函数允许返回 Result,其中 Ok 转换为 EXIT_SUCCESS 而 Err 转换为 EXIT_FAILURE。

在 Rust 1.61.0 中,Termination 特性迎来了稳定,允许我们为自定义枚举实现 Termination 并作为 main 函数的返回值类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 {
        // Maybe print a message here
        ExitCode::from(self as u8)
    }
}

fn main() -> GitBisectResult {
    // Do other things that may return a Error Code
    GitBisectResult::Good
}

默认枚举变体

  • 稳定于:1.62.0

现在,我们可以为枚举的某一变体(Variant)指定 #[default] 来辅助实现 #[derive(Default)],仅有不包含字段的变体才可以用于指定 #[default]:

1
2
3
4
5
6
7
8
9
10
11
12
#[derive(Default, Debug)]
enum MyOption<T> {
    #[default]
    MyNone,

    MySome(T),
}

fn main() {
    let my_none = MyOption::<i32>::default();
    println!("{my_none:?}");
}

泛型关联类型

  • 稳定于:1.65.0

简称 GAT,是 Rust 社区长久以来一直在呼吁的一个特性。这个语法描述起来很简单,它允许你在定义关联类型时使用泛型参数(类型、声明周期、常量):

1
2
3
trait Foo {
    type Bar<'x>;
}

正如 Rust 团队所说,很难用简短的语言来描述这个语法究竟有多大的用处,The push for GATs stabilization 这篇文章能让你对此有更进一步的理解。

let-else 语句

  • 稳定于:1.65.0

这个版本引入了一种新的 let 语句,它允许使用 else 块来处理模式不匹配的情况。else 块必须发散(Diverge),这意味着 break, return 或者 panic! 这类语句:

1
2
3
4
fn main() {
    let input = Option::<i32>::None;
    let Some(_val) = input else { panic!("Expected a value") };
}

跳出任意标记块

  • 稳定于:1.65.0

从该版本开始,break 可以跳出任意一个代码块,这听起来有点像 goto,但实际上,break 只是从代码块的内部跳到了代码块的结尾,而不是 goto 那种任意跳转:

1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() {
    let sum = 'mylabel: {
        let condition = false;
        // do something here that may change condition to true
        if condition {
            break 'mylabel 1;
        }
        // do something here
        2
    };

    println!("{sum}");
}

带字段的枚举的显式判别式

  • 稳定于:1.66.0

在该版本之前,我们只能在所有变体都没有字段的枚举上使用显式判别式:

1
2
3
4
5
6
7
#[repr(u8)]
enum Bar {
    A,
    B,
    C = 42,
    D,
}

现在,即使带有字段,我们仍然可以使用显式判别式:

1
2
3
4
5
6
#[repr(u8)]
enum Foo {
    A(u8),
    B(i8),
    C(bool) = 42,
}

此特性将在跨语言 FFI 中发挥很大的作用。

杂记, Rust
rust 编程语言
本文由作者按照 CC BY 4.0 进行授权
分享

最近更新

  • 『I Wanna』 Best Bye To 2016
  • [译] Rust 中的内联
  • [Rust] 幽灵索引类型与匿名结构体
  • [C++] 深入了解左值与右值
  • Android.bp 中启用 openmp
外部链接
  • 996.icu
  •  此博客的 Github 仓库
  •  Olimi 的个人博客

文章内容

相关文章

2024/04/26

[Rust] 幽灵索引类型与匿名结构体

幽灵索引类型 假设我们有一个这样的类型: 1 2 #[derive(Debug, Clone, Copy)] struct Pair&lt;T, U&gt;(T, U); 并且,该类型保证 T 与 U 始终不会是相同的类型。那么,我们要如何设计一个统一的 get() 方法,使得下面的代码可以实现: 1 2 3 let pair = Pair(1, "hello"); let fi...

2024/02/18

Rust 不透明类型上的生命周期

此文撰写于 Rust stable 1.76.0(即 nightly 1.78.0)版本,由于 nightly 特性不受到 Rust 开发团队的保证,请谨慎甄别本文内容是否仍然适用。 抛出问题 在最前面,我们首先抛出一个问题,为什么下面的代码无法编译? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 use std::fmt::Debug; ...

2024/02/02

从另一个视角看 Rust HRTBs

HRTBs,即高阶 Trait 约束(Higher-Rank Trait Bounds),在 Rust 中是令很多初学者感到莫名其妙的概念,一手 for&lt;'a&gt; S&lt;'a&gt; 的语法更是使得原本就复杂的生命周期更加吓人。 但是,如果从另一个角度对 HRTBs 进行解剖,或许我们能看到不一样的东西。 首先,让我们考虑一个泛型和闭包的应用: 1 2 3 4 5 6 7...

C++ Concept 重载决议探讨

记录在 Qt 重写事件时犯的蠢

© 2024 Nichts Hsu. 保留部分权利。

本站采用 Jekyll 主题 Chirpy

热门标签

编程语言 教程 rust c++ android c++20 usb 翻译 linux qt

发现新版本的内容。