语句与表达式

语句

函数体由一系列的语句和一个可选的结尾表达式构成。目前为止,我们只介绍了没有结尾表达式的函数,不过你已经见过作为语句一部分的表达式。因为 Rust 是一门基于表达式(expression-based)的语言,这是一个需要理解的(不同于其他语言)重要区别。其他语言并没有这样的区别,所以让我们看看语句与表达式有什么区别以及这些区别是如何影响函数体的。

实际上,我们已经使用过语句和表达式。语句(Statements)是执行一些操作但不返回值的指令。表达式(Expressions)计算并产生一个值。让我们看一些例子:

fn main() {
    let y = 6;
}

函数定义也是语句,上面整个例子本身就是一个语句。语句不返回值。因此,不能把 let 语句赋值给另一个变量,比如下面的例子尝试做的,会产生一个错误:

fn main() {
    let x = (let y = 6);
}

$ cargo run
   Compiling functions v0.1.0 (file:///projects/functions)
error: expected expression, found statement (`let`)
 --> src/main.rs:2:14
  |
2 |     let x = (let y = 6);
  |              ^^^
  |
  = note: variable declaration using `let` is a statement

let y = 6 语句并不返回值,所以没有可以绑定到 x 上的值。这与其他语言不同,例如 C 和 Ruby,它们的赋值语句会返回所赋的值。在这些语言中,可以这么写 x = y = 6,这样 xy 的值都是 6;Rust 中不能这样写。表达式会计算出一些值,并且你将编写的大部分 Rust 代码是由表达式组成的。考虑一个简单的数学运算,比如 5 + 6,这是一个表达式并计算出值 11。表达式可以是语句的一部分:语句 let y = 6; 中的 6 是一个表达式,它计算出的值是 6。函数调用是一个表达式。宏调用是一个表达式。我们用来创建新作用域的大括号(代码块),{},也是一个表达式,例如:

fn main() {
    let x = 5;

    let y = {
        let x = 3;
        x + 1
    };

    println!("The value of y is: {}", y);
}

这个表达式:

{
    let x = 3;
    x + 1
}

是一个代码块,它的值是 4。这个值作为 let 语句的一部分被绑定到 y 上。注意结尾没有分号的那一行 x+1,与你见过的大部分代码行不同。表达式的结尾没有分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。在接下来探索具有返回值的函数和表达式时要谨记这一点。

声明语句

Rust 的声明语句可以分为两种,一种为变量声明语句,另一种为 Item 声明语句。变量声明语句。主要是指 let 语句,如:

let a = 8;
let b: Vec<f64> = Vec::new();
let (a, c) = ("hi", false);

由于 let 是语句,所以不能将 let 语句赋给其他值。如下形式是错误的:

let b = (let a = 8);

Item 声明。是指函数(function)、结构体(structure)、类型别名(type)、静态变量(static)、特质(trait)、实现(implementation)或模块(module)的声明。这些声明可以嵌套在任意块(block)中。关于 Item 声明,Rust Reference 中的描述如下:

An item declaration statement has a syntactic form identical to an item declaration within a module. Declaring an item — a function, enumeration, structure, type, static, trait, implementation or module — locally within a statement block is simply a way of restricting its scope to a narrow region containing all of its uses; it is otherwise identical in meaning to declaring the item outside the statement block.

表达式

表达式语句,由一个表达式和一个分号组成,即在表达式后面加一个分号就将一个表达式转变为了一个语句。所以,有多少种表达式,就有多少种表达式语句。

  • 字面表达式(literal expression)

    ();        // unit type
    "hello";   // string type
    '1';       // character type
    15;         // integer type
    
  • 元组表达式(Tuple expression):

    (0.0, 4.5);
    ("a", 4usize, true);
    

    通常不使用一个元素的元组,不过如果你坚持的话,rust 也是允许的,不过需要在元素后加一个逗号:

    (0,); // single-element tuple
    (0); // zero in parentheses
    
  • 结构体表达式(structure expression)由于结构体有多种形式,所以结构体表达式也有多种形式。

    Point {x: 10.0, y: 20.0};
    TuplePoint(10.0, 20.0);
    let u = game::User {name: "Joe", age: 35, score: 100_000};
    some_fn::<Cookie>(Cookie);
    

    结构体表达式一般用于构造一个结构体对象,它除了以上从零构建的形式外,还可以在另一个对象的基础上进行构建:

    let base = Point3d {x: 1, y: 2, z: 3};
    Point3d {y: 0, z: 10, .. base};
    
  • 块表达式(block expression):块表达式就是用花括号{}括起来的一组表达式的集合,表达式间一般以分号分隔。块表达式的值,就是最后一个表达式的值。

    let x: i32 = { println!("Hello."); 5 };
    

    如果以语句结尾,则块表达式的值为():

    let x: () = { println!("Hello."); };
    
  • 范围表达式(range expression): 可以使用范围操作符..来构建范围对象(variant of std::ops::Range):

    1..2;   // std::ops::Range
    3..;    // std::ops::RangeFrom
    ..4;    // std::ops::RangeTo
    ..;     // std::ops::RangeFull
    
  • if 表达式(if expression):

    let a = 9;
    let b = if a%2 == 0 {"even"} else {"odd"};
    
  • 除了以上这些外,还有许多,如:

    • path expression
    • mehond-call expression
    • field expression
    • array expression
    • index expression
    • unary operator expression
    • binary operator expression
    • return expression
    • grouped expression
    • match expression
    • if expression
    • lambda expression
上一页