1 Rust中变量的不可变
代码示例1
js
fn main() {
let x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
比如这里先声明x = 5 再直接修改x为 6 是不可以的。
通过let x = 5 直接声明的x 是不可变的 不可以重新复制。如果想重新赋值需要手动声明成可变的。
代码示例2
js
fn main() {
let x = 5;
println!("The value of x is: {x}");
let x = 6; // 注意这里,重新使用了 let 来定义新变量
println!("The value of x is: {x}");
}
js
fn main() {
let a = 10u32;
let a = 'a';
println!("{}", a);
}
虽然直接给x重新赋值不可以,但是我们可以重复利用这个变量名。这里的意思是说我又重新定义了一个变量x, 只是与之前的变量名称相同。原来的变量名被覆盖了,不可以使用了。
这里重新定义的变量x的类型可以与之前的x 一样,也可以不一样。比如上面的a 从u32变成了char。
2 Rust中变量的可变
代码示例1
js
fn main() {
let mut x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
// 输出
The value of x is: 5
The value of x is: 6
变量从不可变到可变只需要在声明的变量前面加 mut关键字就行。就可以直接再次赋值,赋值类型必须相同。
3 Rust中奇怪的变量赋值
代码示例1
js
fn main() {
let a = 10u32;
let b = a;
println!("{a}");
println!("{b}");
}
这段代码是可以正常运行的,a b 都输出10,在其他语言中这种也是见怪不怪的。只是把u32的a赋值给了b。
再看下面的示例
js
fn main() {
let s1 = String::from("I am a superman.");
let s2 = s1;
println!("{s1}");
println!("{s2}");
}
这段代码跟上面的代码的逻辑是一样的,唯一不一样的是s1的类型是String。但是这段代码运行就会报错。
报错信息
js
Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `s1`
// 借用了移动后的值 `s1`
--> src/main.rs:4:15
|
2 | let s1 = String::from("I am a superman.");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
// 移动发生了,因为 `s1` 的类型是 `String`,而这种类型并没有实现 `Copy` trait."。
3 | let s2 = s1;
| -- value moved here
// 在这里值移动了。
4 | println!("{s1}");
| ^^^^ value borrowed here after move
// 值在被移动后在这里被借用
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
// 如果性能成本可以接受的话,考虑克隆这个值
|
3 | let s2 = s1.clone();
| ++++++++
这里涉及到了Rust中所有权的概念。
知识点
u32 这种类型是固定尺寸类型,而 String 是非固定尺寸类型。一般来说,对于固定尺寸类型,会默认放在栈上;而非固定尺寸类型,会默认创建在堆上,成为堆上的一个资源,然后在栈上用一个局部变量来指向它,如代码中的 s1
在rust中像这u32这种固定尺寸类型,在赋值给新的变量的时候,是在栈上直接复制了一份赋值给新的变量。 对于非固定尺寸类型,s1 是对资源的引用,存储在栈上,将s1赋值给s2的时候,在java中是直接复制了一份引用给s2 ,s1跟s2共存在栈上都指向堆中的资源。Rust 不一样,Rust 虽然也是把字符串的引用由 s1 拷贝到了 s2,但是只保留了最新的 s2 到字符串的指向,同时却把 s1 到字符串的指向给"抹去"了.

