You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.0 KiB

Rust新版解读 | 1.58 | 重点: 格式化字符串捕获环境中的值

众所周知Rust小版本发布非常频繁6周就发布一次因此通常不会有特别值得普通用户关注的内容但是这次1.58版本不同,新增了(stable化了)一个非常好用的功能:在格式化字符串时捕获环境中的值。

Rust 1.58 官方 release doc: Announcing Rust 1.58.0 | Rust Blog

在格式化字符串时捕获环境中的值

在以前,想要输出一个函数的返回值,你需要这么做:

fn get_person() -> String {
    String::from("sunface")
}
fn main() {
    let p = get_person();
    println!("Hello, {}!", p);                // implicit position
    println!("Hello, {0}!", p);               // explicit index
    println!("Hello, {person}!", person = p);
}

问题倒也不大但是一旦格式化字符串长了后就会非常冗余而在1.58后,我们可以这么写:

fn get_person() -> String {
    String::from("sunface")
}
fn main() {
    let person = get_person();
    println!("Hello, {person}!");
}

是不是清晰、简洁了很多?甚至还可以将环境中的值用于格式化参数:

let (width, precision) = get_format();
for (name, score) in get_scores() {
  println!("{name}: {score:width$.precision$}");
}

但也有局限,它只能捕获普通的变量,对于更复杂的类型(例如表达式),可以先将它赋值给一个变量或使用以前的name = expression形式的格式化参数。 目前除了panic!外,其它接收格式化参数的宏,都可以使用新的特性。对于panic! 而言,如果还在使用Rust20152018大版本 ,那panic!("{ident}")依然会被当成 正常的字符串来处理,同时编译器会给予warn提示。而对于2021版本,则可以正常使用:

fn get_person() -> String {
    String::from("sunface")
}
fn main() {
    let person = get_person();
    panic!("Hello, {person}!");
}

输出:

thread 'main' panicked at 'Hello, sunface!', src/main.rs:6:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

比unwrap更危险的unwrap_unchecked

在1.58中为OptionResult新增了unwrap_unchecked方法,与unwrap遇到错误或者空值直接panic不同,unwrap_unchecked遇到错误时处理方式糟糕的多:

fn get_num() -> Option<i32> {
   None
}
fn main() {
    unsafe {
        let n = get_num().unwrap_unchecked();
    }
}

输出如下:

zsh: segmentation fault  cargo run

嗯,段错误了,对比下panic,有一种泪流满面的冲动:我要这不安全的方法何用?

其实,还真有些用:

  • 想要较小的可执行文件时(嵌入式wasm等)该方法就可以大显身手。因为panic会导致二进制可执行文件变大不少
  • 它还可以提高一点性能, 因为编译器可能无法优化掉unwrap的指令分支 虽然它只会增加区区几条分支预测指令