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

相关推荐
gopher95116 小时前
RUST:错误处理 thiserror 详解
开发语言·后端·rust
geovindu18 小时前
rust:Memento Pattern(续)
开发语言·后端·设计模式·rust·行为模式·备忘录模
Kapaseker1 天前
同样 4 行代码,C++ 编译通过,Rust 为什么直接拒绝?
rust
DongQiShanRen1 天前
六根硬件映射(中):双站校验、生克闭环与驱动接口
数据库·人工智能·算法·rust·哈希算法·集成学习
Amos_Web1 天前
Rspack 源码解析(二十五):CssParserAndGenerator 如何把 CSS 变成可 Tree Shaking 的模块
前端·rust·前端框架
Kainy1 天前
Rust重写Photoshop开源项目PhotoCraft:无头命令行修图与AI Agent自动化实战
人工智能·rust·photoshop
I'm Jie1 天前
Rhost v2.0.0 版本发布!!!不止 SSH 终端,内置 AI Agent 支持自然语言操作远程服务器
运维·服务器·rust·开源·ssh·tauri·finalshell
青川Lapis2 天前
RUST:错误处理 thiserror 详解
rust
Source.Liu2 天前
【A11】拥有者模式平台架构笔记
windows·笔记·架构·rust
sayang_shao2 天前
用 Rust 开发 STM32H743:从零搭建一个能烧录、能看日志的项目
stm32·单片机·rust