Rust 学习之变量的可变与不可变

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 到字符串的指向给"抹去"了.

相关推荐
a cool fish(无名)6 小时前
rust-方法语法
开发语言·后端·rust
a cool fish(无名)21 小时前
rust-参考与借用
java·前端·rust
叶 落1 天前
[Rust 基础课程]猜数字游戏-获取用户输入并打印
rust·rust基础
RustFS1 天前
RustFS 如何修改默认密码?
rust
景天科技苑1 天前
【Rust线程池】如何构建Rust线程池、Rayon线程池用法详细解析
开发语言·后端·rust·线程池·rayon·rust线程池·rayon线程池
该用户已不存在2 天前
Zig想要取代Go和Rust,它有资格吗
前端·后端·rust
用户1774125612442 天前
不懂装懂的AI,折了程序员的阳寿
rust
量子位3 天前
vivo自研蓝河操作系统内核开源!Rust开发新机遇来了
rust·ai编程
祈澈菇凉3 天前
rust嵌入式开发零基础入门教程(六)
stm32·单片机·rust
祈澈菇凉3 天前
rust嵌入式开发零基础入门教程(二)
开发语言·后端·rust