返回表达式 return

return 表达式用于函数或者闭包 (closure)中, 从当前函数上下文退出, 返回到函数调用处.

如果函数的返回值为空, 它返回的是 (), 即所谓的 unit struct, 类似于 C 语言中的 void. 比如:

fn do_some() -> () {
  ...
  return;
}

类似于:

void do_some() {
  ...
  return;
}

如果 return obj; 表达式是函数中最后一个表达式, 那么 return 表达式中可以简写为 foo, 看个例子:

#![allow(unused)]
fn main() {
fn max_num(a: i32, b: i32) -> i32 {
  if a > b {
    return a;
  } else {
    return b;
  }
}
}

通常会被简写成以下形式:

#![allow(unused)]
fn main() {
fn max_num(a: i32, b: i32) -> i32 {
  if a > b {
    a
  } else {
    b
  }
}
}

return 表达式的优先级

先看一个基于 RustQuiz#20 修改的示例程序, 考虑考虑程序运行的结果是什么样的:

#![allow(unreachable_code)]
#![allow(unused_braces)]

#[rustfmt::skip]
fn return1() {
    if (return { println!("1") } ) {
    }
}

#[rustfmt::skip]
fn return1_expanded() {
    if (return println!("1")) {
    }
}

fn return1_simplified() {
    println!("1")
}

#[rustfmt::skip]
fn return2() {
    if return { println!("2") } {
    }
}

#[rustfmt::skip]
fn return2_expanded() {
    if return println!("2") {
    }
}

fn return3() {
    if (return {
        println!("3");
    }) {}
}

fn main() {
    return1();
    return1_expanded();
    return1_simplified();
    return2();
    return2_expanded();
    return3();
}

其中, return1() 函数的 MIR 代码如下:

fn return1() -> () {
    let mut _0: ();
    let _1: ();
    let mut _2: std::fmt::Arguments<'_>;
    let mut _3: &[&str];
    let mut _4: &[&str; 1];

    bb0: {
        _4 = const return1::promoted[0];
        _3 = _4 as &[&str] (PointerCoercion(Unsize));
        _2 = Arguments::<'_>::new_const(move _3) -> [return: bb1, unwind continue];
    }

    bb1: {
        _1 = _print(move _2) -> [return: bb2, unwind continue];
    }

    bb2: {
        return;
    }
}

const return1::promoted[0]: &[&str; 1] = {
    let mut _0: &[&str; 1];
    let mut _1: [&str; 1];

    bb0: {
        _1 = [const "1\n"];
        _0 = &_1;
        return;
    }
}

再看一下 return2() 函数的 MIR 代码:

fn return2() -> () {
    let mut _0: ();
    let _1: ();
    let mut _2: std::fmt::Arguments<'_>;
    let mut _3: &[&str];
    let mut _4: &[&str; 1];

    bb0: {
        _4 = const return2::promoted[0];
        _3 = _4 as &[&str] (PointerCoercion(Unsize));
        _2 = Arguments::<'_>::new_const(move _3) -> [return: bb1, unwind continue];
    }

    bb1: {
        _1 = _print(move _2) -> [return: bb2, unwind continue];
    }

    bb2: {
        return;
    }
}

const return2::promoted[0]: &[&str; 1] = {
    let mut _0: &[&str; 1];
    let mut _1: [&str; 1];

    bb0: {
        _1 = [const "2\n"];
        _0 = &_1;
        return;
    }
}

对比 return2() 的 MIR 代码可以发现, 它与 return1() 的代码是相同的. 从这里我们可以学习到, return 表达式比 if 表达式有更高的优先级, 它优先与后面的表达式结合, 组合成 return 表达式, 并作为 if 表达式的条件 (condition).

如何理解呢? return 有更高的优先级, 它优先与大括号中的语句结合, 所以那个大括号是多余的, cargo clippy 会给出相应的提示, 就像下图所示:

return if