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

相关推荐
1nv1s1ble10 小时前
记录rust滥用lazy_static导致的一个bug
算法·rust·bug
华科云商xiao徐15 小时前
用Rust如何构建高性能爬虫
爬虫·rust
景天科技苑17 小时前
【Rust UDP编程】rust udp编程方法解析与应用实战
开发语言·rust·udp·udp编程·rust udp
火柴就是我1 天前
Rust学习之 所有权理解
rust
维维酱1 天前
Rust - Futures
rust
Pomelo_刘金2 天前
Rust: 1.86.0 新版本发布。
rust
Pomelo_刘金2 天前
发布 Rust 1.87.0 —— 以及 Rust 十周年!
rust
susnm2 天前
你的第一个组件
rust·全栈
该用户已不存在2 天前
OpenAI 用 Rust 重写 AI 工具,你的本地开发环境跟上了吗?
前端·javascript·rust