Move语言 表达式

在 Move 语言中,表达式是具有返回值的代码单元。

有返回值的函数调用是一个表达式,它有返回值;整型常数也是一个表达式,它返回整数;其它表达式依此类推。

表达式之间必须用分号";"隔开。

空表达式

类似于 Rust,Move 中的空表达式用空括号表示:

script {
    fun empty() {
        () // this is an empty expression
    }
}

文字表达式

下面的代码,每行包含一个以分号结尾的表达式。

最后一行包含三个表达式,由分号隔开。

script {
    fun main() {
        10;
        10 + 5;
        true;
        true != false;
        0x1;
        1; 2; 3
    }
}

现在我们已经知道了最简单的表达式。但是为什么我们需要它们?以及如何使用它们?这就需要介绍 let 关键字了。

let 关键字

关键字 let 用来将表达式的值存储在变量中,以便于将其传递到其它地方。我们曾经在基本类型章节中使用过 let,它用来创建一个新变量,该变量要么为空(未定义),要么为某表达式的值。

script {
    fun main() {
        let a;
        let b = true;
        let c = 10;
        let d = 0x1;
        a = c;
    }
}

关键字 let 会在当前作用域内创建新变量,并可以选择初始化此变量。该表达式的语法是:let : ;或let = 。

创建和初始化变量后,就可以使用变量名来修改访问它所代表的值了。

在上面的示例中,变量 a 在函数末尾被初始化,并被分配了一个值 c。

等号"="是赋值运算符。它将右侧表达式赋值给左侧变量。示例:a = 10 表示将整数10赋值给变量a。

整型运算符

Move具有多种用于修改整数值的运算符:

运算符 操作 类型  
+ sum uint LHS加上RHS
- sub uint 从LHS减去RHS
/ div uint 用LHS除以RHS
* mul uint LHS乘以RHS
% mod uint LHS除以RHS的余数
<< lshift uint LHS左移RHS位
>> rshift uint LHS右移RHS位
& and uint 按位与
^ xor uint 按位异或
\ or uint 按位或

LHS - 左侧表达式, RHS - 右侧表达式; uint: u8, u64, u128.

"_" 表示未被使用

Move 中每个变量都必须被使用,否则代码编译不会通过, 因此我们不能初始化一个变量却不去使用它。但是你可以用下划线来告诉编译器,这个变量是故意不被使用的。

例如,下面的脚本在编译时会报错:

script {
    fun main() {
        let a = 1;
    }
}

报错:

    ┌── /scripts/script.move:3:13 ───
    │
 33 │         let a = 1;
    │             ^ Unused assignment or binding for local 'a'. Consider removing or replacing it with '_'
    │

编译器给出明确提示:用下划线来代替变量名。

script {
    fun main() {
        let _ = 1;
    }
}

变量屏蔽

Move 允许两次定义同一个的变量,第一个变量将会被屏蔽。但有一个要求:我们仍然需要"使用"被屏蔽的变量。

script {
    fun main() {
        let a = 1;
        let a = 2;
        let _ = a;
    }
}

在上面的示例中,我们仅使用了第二个a。第一个a实际上未使用,因为a在下一行被重新定义了。所以,我们可以通过下面的修改使得这段代码正常运行。

script {
    fun main() {
        let a = 1;
        let a = a + 2;
        let _ = a;
    }
}

块表达式

块表达式用花括号"{}"表示。块可以包含其它表达式(和其它代码块)。函数体在某种意义上也是一个代码块。

script {
    fun block() {
        { };
        { { }; };
        true;
        {
            true;

            { 10; };
        };
        { { { 10; }; }; };
    }
}

块返回值

上面我们了解到代码块是一个表达式,但是我们没有介绍为什么它是一个表达式以及代码块的返回值是什么。

代码块可以返回一个值,如果它后面没有分号,则返回值为代码块内最后一个表达式的值。

听起来不好理解,我们来看下面的例子:

script {
    fun block_ret_sample() {

        // since block is an expression, we can
        // assign it's value to variable with let
        let a = {

            let c = 10;

            c * 1000  // no semicolon!
        }; // scope ended, variable a got value 10000

        let b = {
            a * 1000  // no semi!
        };

        // variable b got value 10000000

        {
            10; // see semi!
        }; // this block does not return a value

        let _ = a + b; // both a and b get their values from blocks
    }
}

代码块中的最后一个表达式(不带分号)是该块的返回值。

Move 语言的作用域是指绑定生效的代码区域。换句话说,变量存在于作用域中。Move 语言的作用域是由花括号扩起来的代码块,它本质上是一个块。定义一个代码块,实际上是定义一个作用域。script { fun scop ...