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

相关推荐
脑极体1 小时前
蓝河入海:Rust先行者vivo的开源之志
开发语言·后端·rust·开源
badmonster02 小时前
实时代码库索引:用 CocoIndex 构建智能代码搜索的终极方案
python·rust
黛色正浓5 小时前
【React】极客园案例实践-项目搭建和登录模块
前端·react.js·rust
思密吗喽5 小时前
npm install 报错,解决 node-sass@4.14.1 安装失败问题
rust·npm·node.js·毕业设计·sass·课程设计
青云交6 小时前
深度实战:Rust交叉编译适配OpenHarmony PC——ansi_term完整适配案例
rust·交叉编译·命令行工具·openharmony pc·ansi_term·适配案例·终端颜色
星释6 小时前
Rust 练习册 106:太空年龄计算器与宏的魔法
开发语言·后端·rust
ALex_zry7 小时前
系统编程的基石:补码循环溢出与Rust变量绑定的深度探索
开发语言·后端·rust
ALex_zry7 小时前
Rust语言基础分析与C++对比:系统编程的现代演进
java·c++·rust
星释7 小时前
Rust 练习册 105:从零开始实现链表数据结构
数据结构·链表·rust
四问四不知17 小时前
Rust语言进阶(结构体)
开发语言·后端·rust