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

相关推荐
大鱼七成饱7 小时前
Rc和RefCell:严父Rust的叛逆小儿子
rust
l1t9 小时前
使用DeepSeek辅助测试一个rust编写的postgresql协议工具包convergence
开发语言·postgresql·rust·协议·datafusion
Kiri霧11 小时前
Rust数组与向量
开发语言·后端·rust
特立独行的猫a11 小时前
Rust语言入门难,难在哪?所有权、借用检查器、生命周期和泛型介绍
开发语言·后端·rust
yihai-lin15 小时前
Rust/C/C++ 混合构建 - Cmake集成Cargo编译动态库
c语言·c++·rust
fcm1915 小时前
(6) tauri之前端框架性能对比
前端·javascript·rust·前端框架·vue·react
yihailin1 天前
Rust/C/C++ 混合构建 - Cmake集成Cargo编译动态库
rust
李剑一1 天前
为了免受再来一刀的痛苦,我耗时两天开发了一款《提肛助手》
前端·vue.js·rust
红尘散仙1 天前
使用 Tauri Plugin-Store 实现 Zustand 持久化与多窗口数据同步
前端·rust·electron