文章目录
1. Rust 中的变量
我们从上一篇文章中了解到在 Rust
中定义的变量默认情况下是不可变的。这是 Rust
语言为保证其安全性和简单并发性方式的代码而规定的特性。Rust
考虑的是,在设计程序时,假设代码刚开始定义一个值,并且该值永远也不会改变,但是当代码多了后,再另一部分忘记了刚开始的设想,又改变了那个值,那么将可能导致之前的代码不会按预期的效果执行下去。那么 Rust
就会改变这一现状,当你声明一个值且不会再改变它时,它就真的不能再改变,Rust
编译器会帮你去保证这一点,从而使你构建的代码更容易阅读和推理。
2. Rust 的默认不可变变量(immutable)
和往常一样,我们使用 Cargo
新建一个项目,用来做相关的实验。创建成功后的目录结构如下。
imaginemiracle:rust_projects$ cargo new variables
imaginemiracle:rust_projects$ cd variables/
imaginemiracle:variables$ tree
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
打开 src/main.rs
源文件,并将代码更新为下面代码。
fn main() {
let val = 27149; // 陈永仁警号——《无间道》
println!("The value of val is: {val}");
val = 4927; // 刘建明警号——《无间道》
println!("The value of val is: {val}");
}
这里我们尝试对 Rust
的默认变量做修改。OK!来运行一下看看会发生什么。
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
error[E0384]: cannot assign twice to immutable variable `val`
--> src/main.rs:7:5
|
3 | let val = 27149; // 陈永仁警号——《无间道》
| ---
| |
| first assignment to `val`
| help: consider making this binding mutable: `mut val`
...
7 | val = 4927; // 刘建明警号——《无间道》
| ^^^^^^^^^^ cannot assign twice to immutable variable
For more information about this error, try `rustc --explain E0384`.
error: could not compile `variables` due to previous error
编译器报错:cannot assign twice to immutable variable
这里可以看到编译器告诉我们 “不能对不可变变量赋值两次,要不要将变量声明为 mut 的可变变量”。
3. Rust 的可变变量(mutable)
既然默认的变量是不可改变的,那么将如何让变量可变呢?关于这一点,若是阅读过本系列第 4
篇文章的伙伴应该已经清楚了。我们需要在变量名前添加 mut
关键字来说明此变量将被声明为可变变量 (mutable)
。
让我们将上面的 src/main.rs
修改为下面代码:
fn main() {
let mut val = 27149; // 陈永仁警号——《无间道》
println!("The value of val is: {val}");
val = 4927; // 刘建明警号——《无间道》
println!("The value of val is: {val}");
println!("对不起,我是警察。");
}
那么这个时候再次运行该程序呢:
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.29s
Running `target/debug/variables`
The value of val is: 27149
The value of val is: 4927
对不起,我是警察。
Oh,我们已经正确的改变了可变变量的值。
[注]:在 Rust 中,变量的可变性,取决于开发人员。
4. Rust 的常量(Constants)
有 C
或 C++
基础的朋友一定清楚什么是常量。Rust
中也有常量(const
),被声明为常量后,那么程序将不允许再更改该常量的值,这里看起来与 Rust
中的默认变量特性很相似,都是不允许被修改的,但两者也存在一定的差异。
差别如下:
- 首先要明确的一点是,
const
修饰的常量是不允许使用mut
的,即常量必须保证自己是不可变的,这一点是不可违反的; - 常量使用
const
关键字修饰,而默认的不可变变量由let
关键字修饰; - 使用
const
修饰声明的常量必须注明其数据类型,而let
则可以不显示注明,依靠Rust
编译器自动识别变量类型; - 常量只能赋值为常量表达式,而非仅再运行时计算的数值。
下面是一个常量声明的例子:
fn main() {
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
}
常量的名称为 THREE_HOURS_IN_SECONDS
,其值赋值为 60
(一分钟的秒数)乘以 60
(一小时的分钟数)乘以 3
(需要计算的小时数)。
另外一点需要注意的是:Rust
中的常量命名规则,需使用全大写的单词,之间需要用下划线间隔。
编译器能够在编译时评估一组有限的操作,这让我们可以选择以更容易理解和验证的方式写出这个值,而不是将此常量设置为值 10,800
。
这样做的好处是可以更清楚的将开发时的常量含义传达给代码的 “未来守护者”。
4.1. 不惯着他会怎样
有时候我们总会有种 “杠精” 想法(不,我们这是为了更透彻的理解)。
(1) 如果我非要在 const
修饰的常量前加上 mut
会怎样?
(2) 要是我在声明常量时没有注明数据类型会怎样?
(3) 如果我就是要在 Rust
种修改 const
修饰的常量怎么办?
(4) 如果我不按你规定的规则命名常量会怎样?
来吧,让我们逐一的做实验,让实践验证我们的杠精式疑虑。
验证 (1):
用下面代码验证
fn main() {
const mut THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
}
尝试执行:
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
error: const globals cannot be mutable
--> src/main.rs:3:11
|
3 | const mut THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
| ----- ^^^ cannot be mutable
| |
| help: you might want to declare a static instead: `static`
error: could not compile `variables` due to previous error
OK!编译器直接说常量式不可以变成可变变量。(编译器不会让过。)
验证 (2):
用下面代码验证
fn main() {
const THREE_HOURS_IN_SECONDS = 60 * 60 * 3;
}
尝试执行:
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
error: missing type for `const` item
--> src/main.rs:3:11
|
3 | const THREE_HOURS_IN_SECONDS = 60 * 60 * 3;
| ^^^^^^^^^^^^^^^^^^^^^^ help: provide a type for the constant: `THREE_HOURS_IN_SECONDS: i32`
error: could not compile `variables` due to previous error
OK !编译器说 missing type for 'const' item
,检测到我们的语法有问题,说 const
这块缺少类型。(编译器不让过。)
验证 (3):
用下面代码验证
fn main() {
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
THREE_HOURS_IN_SECONDS = 12;
}
尝试执行:
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
error[E0070]: invalid left-hand side of assignment
--> src/main.rs:6:28
|
6 | THREE_HOURS_IN_SECONDS = 12;
| ---------------------- ^
| |
| cannot assign to this expression
For more information about this error, try `rustc --explain E0070`.
error: could not compile `variables` due to previous error
OK !编译器不允许这样赋值。(编译器不让过。)
验证 (4):
用下面代码验证
fn main() {
const three_HoursIn_seconds: u32 = 60 * 60 * 3;
println!("The result: {three_HoursIn_seconds}");
}
尝试执行:
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
warning: constant `three_HoursIn_seconds` should have an upper case name
--> src/main.rs:4:11
|
4 | const three_HoursIn_seconds: u32 = 60 * 60 * 3;
| ^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to upper case: `THREE_HOURS_IN_SECONDS`
|
= note: `#[warn(non_upper_case_globals)]` on by default
warning: `variables` (bin "variables") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/variables`
The result: 10800
哎哟喂 ~,编译器只是警告了一下我们,但是要注意的是,编译器提示我们说,常量还是应该有个全大写的名字。(尊重一下他老人家吧,就规规矩矩的吧。)
5. 覆盖(Shadowing)
Rust
中允许声明一个与先前变量同名的新变量,此时第一个变量则被第二个新的变量覆盖(Shadowing
),这将意味着从第二个新声明的变量以后,编译器再看到的同样名称的变量将发生改变(并非存在两个同名变量)。覆盖(Shadowing
)了的变量也有生命周期的限制。下面我们看一个例子(将 src/main.rs
内容修改为如下代码):
fn main() {
let num = 2048;
let num = num / 2; // shadowing
{
let num = num / 2;
println!("The value of num in the inner scope is: {num}");
} // 使用 {} 设定变量声明周期
println!("The value of num is: {num}");
}
分析:
该段代码首先为 num
绑定一个数值为 2048
。接着再通过 let num
重复创建了一个新的变量 num
,并为其赋值为原始值除以 2
,那么此时的 num
的值应该为 1024
。
之后在一个大括号限制的范围内再次使用 let num
覆盖并创建了一个新的 num
,赋值为之前的值除以 2
,这里的新创建的 num
的声明周期到大括号结束也随之结束,那么 shadowing
的效果也随之消失。在大括号之外再次查看 num
的值将会恢复到大括号开始时的状态。
让我们来执行看看分析是否正确:
imaginemiracle:variables$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/variables`
The value of num in the inner scope is: 512
The value of num is: 1024
Boy: おかしいなあ,这样看起来也是在修改变量值呀!
Girl: 是的,这样的确看起来像是在改变变量的值。
Boy: ???Rust
干嘛这么费劲还要折腾一个 mut
哇!
事实上 mut
与 shadowing
过程还是有的区别的,使用 let
重新声明并覆盖掉之前的变量,该过程是的的确确的创建了一个全新的变量,因此我们可以任意的更换白能量的类型,但使用相同的名字。让我们通过一个例子说明(将 src/main.rs
内容修改为如下代码):
fn main() {
let hello = "hello world!";
println!("The string is: {hello}");
let hello = hello.len();
println!("The string length is: {hello}");
}
分析:
来看这段代码,首先声明了一个名为 hello
的变量,为其绑定的值为 “hello world!”
,这里并没有显式的注明其数据类型,因为 Rust
编译器会自动识别它为字符串类型。而在下面使用 let hello
重新声明了一个同名变量,为其绑定的值为原 hello
变量的字符串长度,同样没有显式注明数据类型,编译器会自动检测为整型(Rust
中默认整数类型为 i32
)。那么这里 hello
实际上已经不仅改变了值,其代表的数据类型也发生了改变,除了名称未改变,其它的已经算是完全的改头换面了。
该段代码的执行结果如下:
imaginemiracle:variables$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/variables`
The string is: hello world!
The string length is: 12
那么如果使用 mut
会发生什么情况呢?来看看。
(将 src/main.rs
内容修改为如下代码):
fn main() {
let mut hello = "hello world!";
println!("The string is: {hello}");
hello = hello.len();
println!("The string length is: {hello}");
}
尝试执行它:
imaginemiracle:variables$ cargo run
Compiling variables v0.1.0 (/home/imaginemiracle/Miracle/Code/rust_projects/variables)
error[E0308]: mismatched types
--> src/main.rs:7:13
|
3 | let mut hello = "hello world!";
| -------------- expected due to this value
...
7 | hello = hello.len();
| ^^^^^^^^^^^ expected `&str`, found `usize`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `variables` due to previous error
编译器将会报错,提示我们类型不匹配,无法将整型赋值给字符串类型的变量。
#Review
OK ! 到目前为止我们已经清楚的了解了如何声明变量以及,变量是如何工作的。接下来将要看看 Rust
中更多的数据类型。
Boys and Girls!!!
准备好了吗?下一节我们要开始做个小练习了哦!
不!我还没准备好,让我先回顾一下之前的。
上一篇《Rust 编写猜字谜游戏——Rust语言基础04》
我准备好了,掛かって来い(放马过来)!
下一篇《Rust 中的基本数据类型——Rust语言基础06》
觉得这篇文章对你有帮助的话,就留下一个赞吧v*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用知识共享署名-非商业性-相同方式共享 4.0 国际许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/125526797