变量绑定与解耦

命名规范

  • Crates 包 无
  • Modules snake_case
  • Types UpperCamelCase
  • 特征Traits UpperCamelCase
  • 枚举 Enumerations UpperCamelCase
  • 结构体 Structs UpperCamelCase
  • 函数 Functions snake_case
  • 方法 Methods snake_case
  • 通用构造器 General constructors new or with_more_details
  • 转换构造器 from_some_other_type
  • 宏 Macros snake_case!
  • 局部变量 Local variables snake_case
  • 静态类型 Statics SCREAMING_SNAKE_CASE
  • 常量Constants SCREAMING_SNAKE_CASE
  • 类型参数Type parameters UpperCamelCase
  • 生命周期 Lifetimes 小写字母 'a 'de 'src

变量绑定

1
let a = "hello world";

在rust里面我们给赋值取了个另外一个名字,叫做 变量绑定。

为什么不用赋值而是绑定?这就涉及到rust最核心的原则—— 所有权。
任何的内存对象都是有主任的,而且一般情况下完全属于它的主人。

绑定就是把一个对象绑定给你个变量,让这个变量成为他的主人。该对象之前的主人就会失去对他的所有权。有点像我们cpp智能指针里的unique_ptr

变量可变性

rust的变量在默认情况下是不可变的

1
2
3
4
5
6
fn main() {
let x = 5;
println!("The value of x is: {}", x);
x = 6;
println!("The value of x is: {}", x);
}

->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: consider making this binding mutable: `mut x`
3 | println!("The value of x is: {}", x);
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable

error: aborting due to previous error

cannot assign twice to immutable variable x

下划线开头来忽略未使用的变量

如果创建了一个变量但是不用,rust会给你一个警告,如果希望rust不要警告可以用下划线打头。

1
2
3
4
fn main() {
let _x = 5;
let y = 10;
}

变量解构

let 表达式不仅仅用于变量绑定,还能进行复杂变量的结构: 从一个相对复杂的变量中匹配出该变量的一部分内容

1
2
3
4
5
6
7
8
fn main(){
let (a, mut b): (bool,bool) = (true,false);
// a = true, b = false b可变
println!("a = {:?}, b={:?}",a,b);

b = true;
assert_eq!(a,b);
}

解构式赋值

我们可以在赋值语句的左式中使用元组、切片和结构体模式了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Struct {
e:i32
}

fn main(){
let (a, b, c, d, e);

(a,b) = (1,2);
// _ 代表匹配一个值,但是不关心具体是啥
[c,...,d,_] = [1,2,3,4,5];
Struct {e,..} = Struct {e:5};

assert_eq!([1,2,1,4,5],[a,b,c,d,e]);
}

这种使用方式跟之前的 let 保持了一致性,但是 let 会重新绑定,而这里仅仅是对之前绑定的变量进行再赋值。

变量和常量之间的差异

变量的值不能更改可能让我们想起 constant常量,和不可变变量一样,常量也是绑定到一个常量名且不允许更改的值,但是常量和变量之间存在1点差异

  • 常量不准用mut, 不仅仅默认不可变,而且始终不可变
  • const 关键字 而不是 let 关键字

example:

1
const MAX_POINTS: u32 = 100_000;

常量可以在任意作用域内声明,包括全局作用域,在声明的作用域内,常量在程序运行的整个过程中都有效。对于需要在多处代码共享一个不可变的值时非常有用,例如游戏中允许玩家赚取的最大点数或光速。

变量遮蔽

Rust 允许声明相同的变量名,后面的会遮蔽掉前面的

1
2
3
4
5
6
7
8
9
10
11
12
13
14

fn main(){
let x = 5;

//main的作用域内对前面的遮蔽
let x = x + 1;

{
let x = x * 2;
println!("The value of x in the inner scope is:{}",x);
}

println!("The value of x in the outer scope is:{}",x);
}

首先把 5 绑定到 x, 然后重复使用 let x = ... 来遮蔽前面的x, 并取原来的值加上 1 , 所以 x 变成了 6. 第三个 let语句同样这笔前面的 x , 取之前的值并乘上 2, 得到的x 最终为 12 .

第二个 let 生成的是一个完全的新的变量,两个变量只是刚好名字一样。涉及到了一种内存的再分配,而mut声明的变量,可以修改同一个内存地址上面的值,并不会发生内存对象的再分配。性能要更好。

例如一个程序要统计一个空格字符串的空格数量:

1
2
let spaces = "   ";
let spaces = spaces.len();

第一个 spaces 变量是一个字符串类型,而第二个则是一个权限的变量并且和第一个共享名字。

相反我们可以重复使用更简单的 spaces 变量名

1
2
let mut spaces = "   ";
spaces = spaces.len();

运行的话就会发现编译器报错了

rust对类型的要求很严格,不允许把整数类型 usize赋值给字符串类型。 usize是一种CPU相关的整数类型。