前言
前几篇文章中,我们已经对 Rust 有了一个初步的了解,并通过一个 猜数游戏 的小程序的开发,抢先接触了 Rust 的一些语法特性,但大多都是浅尝辄止,未曾深入,从这个章节开始,我们就来一步步地深入学习这些语法特性,力求将这些语法特性都吃透,并能够灵活应用。
接触程序,我们首先需要接触变量,所以,我们今天这篇文章就以变量与可变性 作为切入点正式进入 Rust 的语法世界。
let
我们在前几章已经反复讲了好多次 let
相关的内容了,这边就不再赘述了,总得来说就是:
使用 let 可以定一个不可变的变量,如果想要这个变量可变,需要在 let 后加一个 mut 关键字注明,否则会报错。变量定义后,可以再次用 let 对同名变量进行重新定义(Shadowing),常用与变量的类型转换。
具体的使用示例,可以查看本专题的前几个章节,这边就不再赘述了。
需要特别注意的是,let
变量是不能再全局作用域中定义的,通常我们都是在:函数作用域 、代码块作用域 和循环作用域 内部使用。如果在全局作用域上使用 let
,你将会看到 Rust 抛出的报错:
这也是 Rust 的 let
与 ts/js 的中的 let
很大的不同点,在 ts/js 当中,我们可以毫无顾忌的在全局作用域上使用 let
关键字定义些变量并在全局范围内可以随意调用和修改。而到了 Rust ,我们就要改变我们这个使用习惯了,不然得到的只会是 Rust 的无情报错。
变量与常量
在 typescript
当中,可以使用使用 let
定义变量,用于存储一些可变的值,同时也可以使用 const
定义常量,用于定义一些永远不变的值。而在 Rust 也是一样的,我们同样可以使用 const
关键字用来定义一些恒定不变的值,即常量。
有同学可能会有疑问,在 Rust 当中,let
在没有声明 mut
的时候,也是不可变的,那不是跟 const
的作用一样了吗?多一个 const
有什么用呢?
-
不可使用 mut :常量永远都是不可变的,不可以使用
mut
关键字。 -
使用 const 关键字 :在 Rust 当中,声明常量跟在
typescript
当中声明常量的关键字是一样的,都是const
。 -
类型必须显示标注 :与
typescript
中常量可以根据初始赋值时变量的类型自动推论不同,在 Rust 当中,常量的类型必须显式声明,否则会报错 -
可在全局作用域中声明 :与
let
不同的是,const
关键字与ts/js
一样,都可以在全局作用域范围内生命。 -
常量只能绑定常量表达式:常量只能绑定常量表达式,无法绑定到函数的调用结果,或者是只能在运行时产生的值。
-
在作用域内持续有效:在程序运行期间,常量在其声明的作用域内是始终有效的。
-
命名规范 : 在 Rust 当中,常量的命名规范是全大写,多个单词之间使用
_
分隔,如:FIRST_NAME
上面的代码其他的应该都很容易理解,有一点比较让人费解的就是 后面的赋值与中的
10_000
,或许有些同学不清楚什么意思,这其实是我们在定一个数字的时候,可以用_
对数字进行格式化,增加数字的可读性,其实上面的10_000
就是代表10000
这个数字。其实这个特性目前也已经被js
支持了,我们在最新的chrom
浏览器的控制台,直接使用这种方式定义数值也是能够正常使用的:
变量的隐藏(shadowing)
前端开发的同学应该都很清楚,以下这两种方式,在 JS/TS 中是不允许的:
typescript
let num = 10;
// ❌ 不能重复得使用 let 进行同名变量的定义
let num = 20;
const name = "kiner";
// ❌ 不能重复得使用 const 进行同名常量的定义
const name = 18;
然而,在 Rust 当中,将会颠覆你之前的使用习惯:
rust
let num: i32 = 10;
// ✅ 这样是合法的,不会报错的,我们在这行之后,num 的类型是 u32,而在这之前,类型则是 i32
let num: u32 = 100;
const NAME: $str = "kiner";
// ✅ 这样是合法的,不会报错的,我们在这行之后,NAME 的类型是 u32,而在这之前,类型则是 &str
const NAME: u32 = 10;
在 Rust 当中,我们把这种能够重新定义同名变量的特性称之为:Shadowing(隐藏) ,即:变量隐藏。我们在上几篇文章当中,也有初步的接触到变量隐藏的概念,当时是为了实现一个猜数游戏,利用变量隐藏的特性,实现类将字符串类型的用户输入转换成整型的任务。
rust
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("读取行失败");
println!("你猜测的数是:{}", guess);
// 类型转换,将原本用户输入的字符串转换成之后方便比较的整型
let guess: i64 = match guess.trim().parse() {
// 如果转换成功,则将其值赋值给 guess
Ok(num) => num,
// 如果转换失败,则使用 continue 关键字跳过本次循环,继续下一次循环,让用户重新输入
Err(_) => {
println!("请输入一个数字!");
continue;
},
};
总结一下,就是我们可以用后面的 let
关键字定义的同名变量隐藏到前面的同名变量,并且声明的新变量的类型可以跟之前的类型是不一样,如之前是整型,你可以重新声明成字符串类型。
结语
至此,我们已经详细的了解了在 Rust 当中定义变量和常量的方式,也了解了变量的可变性以及 Rust 与其他语言很大的一个不同点:变量隐藏(Shadowing)的概念、使用场景等等,相信大家都已经对变量的相关知识已经更加清晰了吧。