介绍
Move 中局部变量使用let关键字定义,变量可以直接修改。
声明
##let x; // 声明一个变量x = 0; // 赋值##let x = 1; // 声明一个变量并赋值let x = x + x;
赋值
变量必须在使用前进行赋值操作。
let x;x + x; // ERRORlet x;if (cond) x = 0;x + x; // ERRORlet x;while (cond) x = 0;x + x; // ERROR
命名
变量名可以包含_、a-Z、0-9。但是变量名必须是以_或者字母a-z开头。
// valid namelet x = e;let _x = e;let _A = e;let x0 = e;let xA = e;let foo_11 = e;// invalid namelet X = e; // ERRORlet Foo = e; // ERROR
注释
通常情况下,Move 可以自动识别变量类型,不过变量类型显性表示出来,可以让代码更可读、更清晰:
let x: T = e; // 变量x的类型为T,赋值为e
address 0x1 {module Example {struct S { x: u64, y: u64 }fun annotated() {let u: u8 = 0;let b: vector<u8> = b"hello";let q: address = @0x0;let (x, y): (&u64, &mut u64) = (&0, &mut 1);let S { x, y: f2 }: S = S { x: 0, y: 1 };}}}
一些特殊情况下,Move 编译器无法识别变量类型,则必须显性表示:
let _v1 = Vector::empty(); // ERROR!// ^^^^^^^^^^^^^^^ Could not infer this type. Try adding an annotationlet v2: vector<u64> = Vector::empty(); // NO ERROR
下面情况下,Move 类型编译器野无法识别变量类型。return和abort函数能返回任何类型:
let a: u8 = return ();let b: bool = abort 0;let c: signer = loop ();let x = return (); // ERROR!// ^ Could not infer this type. Try adding an annotationlet y = abort 0; // ERROR!// ^ Could not infer this type. Try adding an annotationlet z = loop (); // ERROR!// ^ Could not infer this type. Try adding an annotation
元组
let () = ();let (x0, x1) = (0, 1);let (y0, y1, y2) = (0, 1, 2);let (z0, z1, z2, z3) = (0, 1, 2, 3);
结构
let在赋值struct类型时,可以一次创建多个局部变量,并初始化为此struct中的字段:
## example 1struct T { f1: u64, f2: u64 }let T { f1: local1, f2: local2 } = T { f1: 1, f2: 2 };// local1: u64,local2: u64## example 2address 0x1 {module Example {struct X { f: u64 }struct Y { x1: X, x2: X }fun new_x(): X {X { f: 1 }}fun example() {let Y { x1: X { f }, x2 } = Y { x1: new_x(), x2: new_x() };assert!(f + x2.f == 2, 1);let Y { x1: X { f: f1 }, x2: X { f: f2 } = Y { x1: new_x(), x2: new_x() };assert!(f1 + f2 == 2, 1);}}}
struct有两个作用:识别绑定的字段和变量名称。
let X { f } = e;let X { f: f } = e; // 这两种写法等价let Y { x1: x, x2: x } = e; // let 关键字在元组赋值时不能声明两个相同的名称 x
引用
在下面的struct事例中,使用let关键字后,绑定的值实际上是被移动了:销毁了struct和它绑定的值:
## let 之后,T { f1: 1, f2: 2 } 被销毁struct T { f1: u64, f2: u64 }let T { f1: local1, f2: local2 } = T { f1: 1, f2: 2 };
如果使用let关键字后不让他自动销毁,可以引用此struct,例如:
let t = T { f1: 1, f2: 2 };let T { f1: local1, f2: local2 } = &t;
忽略某些值
使用let关键字,还可以做到忽略部分值。使用_作为前缀,不会引入新的变量:
fun three(): (u64, u64, u64) {(0, 1, 2)}let (x1, _, z1) = three();let (x2, _y, z2) = three();assert!(x1 + z1 == x2 + z2)
语法解释
let (x, y): (u64, u64) = (0, 1);// ^ local-variable// ^ pattern// ^ local-variable// ^ pattern// ^ pattern-list// ^^^^ pattern-list// ^^^^^^ pattern-or-list// ^^^^^^^^^^^^ type-annotation// ^^^^^^^^ initializer// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ let-bindinglet Foo { f, g: x } = Foo { f: 0, g: 1 };// ^^^ struct-type// ^ field// ^ field-binding// ^ field// ^ local-variable// ^ pattern// ^^^^ field-binding// ^^^^^^^ field-binding-list// ^^^^^^^^^^^^^^^ pattern// ^^^^^^^^^^^^^^^ pattern-or-list// ^^^^^^^^^^^^^^^^^^^^ initializer// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ let-binding
