Rust01-变量绑定与解构

举报
林太白 发表于 2025/06/26 14:34:49 2025/06/26
【摘要】 Rust01-变量绑定与解构

Rust01-变量绑定与解构

👉 手动设置变量

🍎 手动设置变量的原因

大多数语言中,要么只支持声明可变的变量(为编程提供了灵活性)

要么只支持声明不可变的变量(例如函数式语言–为编程提供了安全性)

而 Rust 选择了两者都要,既要灵活性又要安全性,还有运行性能上的提升

🍎常见语言的可变变量和不可变变量

// JavaScript

// 可变变量
let x = 10;
x = 20;  // 有效,let 声明的变量是可变的

// 不可变常量
const y = 30;
// y = 40;  // 报错,const 声明的变量是不可变的

//Python 
# 可变变量
x = 10
x = 20  # 这是有效的,变量 x 是可变的

# 不可变对象
x = (1, 2, 3)  # 创建一个元组
# x[0] = 10  # 会抛出错误:'tuple' object does not support item assignment

// Java 
// 声明可变和不可变的变量,使用final 将变量声明为不可变的(常量)

// 可变变量
int x = 10;
x = 20;  // 这是有效的,变量 x 是可变的

// 不可变变量
final int y = 30;
// y = 40;  // 编译错误,不能修改 final 变量 y

👉变量命名

同理,一般遵循Rust的命名规范,排除保留字和额外留存的关键字keywords

🍎 现在在使用的关键字

关键字 描述
as 强制类型转换,或use 和 extern crate包和模块引入语句中的重命名
break 立刻退出循环
const 定义常量或原生常量指针(constant raw pointer)
continue 继续进入下一次循环迭代
crate 链接外部包
dyn 动态分发特征对象
else 作为 if 和 if let 控制流结构的 fallback
enum 定义一个枚举类型
extern 链接一个外部包, 或者一个宏变量(该变量定义在另外一个包中)
false 布尔值 false
fn 定义一个函数或 函数指针类型 (function pointer type)
for 遍历一个迭代器或实现一个 trait 或者指定一个更高级的生命周期
if 基于条件表达式的结果来执行相应的分支
impl 为结构体或者特征实现具体功能
in for 循环语法的一部分
let 绑定一个变量
loop 无条件循环
match 模式匹配
mod 定义一个模块
move 使闭包获取其所捕获项的所有权
mut 在引用、裸指针或模式绑定中使用,表明变量是可变的
pub 表示结构体字段、impl 块或模块的公共可见性
ref 通过引用绑定
return 从函数中返回
Self 实现特征类型的类型别名
self 表示方法本身或当前模块
static 表示全局变量或在整个程序执行期间保持其生命周期
struct 定义一个结构体
super 表示当前模块的父模块
trait 定义一个特征
true 布尔值 true
type 定义一个类型别名或关联类型
unsafe 表示不安全的代码、函数、特征或实现
use 在当前代码范围内(模块或者花括号对)引入外部的包、模块等
where 表示一个约束类型的从句
while 基于一个表达式的结果判断是否继续循环

🍎保留以备将来使用

跟其他语言差不多会预留一些关键变量,同样一些原生的我们也尽量不进行使用

关键字 描述
abstract 保留以备将来使用
async 保留以备将来使用
await 保留以备将来使用
become 保留以备将来使用
box 保留以备将来使用
do 保留以备将来使用
final 保留以备将来使用
macro 保留以备将来使用
override 保留以备将来使用
priv 保留以备将来使用
try 保留以备将来使用
typeof 保留以备将来使用
unsized 保留以备将来使用
virtual 保留以备将来使用
yield 保留以备将来使用

🍎原生类型的

这里面就是一些c和其他之类的关键字和保留字,参考我们学的c语法即可

🍎原生标识符

当然,如果上面的说法你都反对,也可以使用原生标识符(Raw identifiers)帮助我们使用通常不能使用的关键字,带有 r# 前缀

比如我现在使用match作为函数名

fn match(needle: &str, haystack: &str) -> bool {
    haystack.contains(needle)
}

这个时候报警告给我,也会友好的给我们一个写法提示

error: expected identifier, found keyword `match`
  --> src\modules\user.rs:30:4
   |
30 | fn match(needle: &str, haystack: &str) -> bool {
   |    ^^^^^ expected identifier, found keyword
   |
help: escape `match` to use it as an identifier
   |
30 | fn r#match(needle: &str, haystack: &str) -> bool {
   |    ++

加上我们前缀以后,ok,这个时候运行和输出都正常

fn r#match(needle: &str, haystack: &str) -> bool {
    haystack.contains(needle)
}
fn main() {
    assert!(r#match("foo", "foobar"));
    println!("World, hello");
}

// World, hello

原生标识符允许我们使用任何单词作为标识符,即使该单词恰好是保留关键字。

还允许我们使用其它 Rust 版本编写的库,也就是旧版本你的代码迁移过来往前面加一个r#照样能够使用

fn main() {
    let r#async = 10;
    let r#await = 20;
    
    println!("r#async: {}, r#await: {}", r#async, r#await);
}

👉变量绑定

Rust把赋值的过程起了另一个名字:变量绑定,其实主要也是为了强调Rust 核心原则——所有权

let a = "hello world" 

👉变量可变性

Rust 的变量默认不可变,但通过 mut 关键字我们可以让变量变为可变的

🍎好处

要改变不可变变量,就要重新创建一个新的变量,涉及到内存对象的再分配

而可变变量最大的好处就是使用上的灵活性和性能上的提升

🍎示例

下面这段代码运行会给我们一个报错提示

fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

报错cannot assign twice to immutable variable x(无法对不可变的变量进行重复赋值)

  --> src\main.rs:26:5
   |
24 |     let x = 5;
   |         - first assignment to `x`
25 |     println!("The value of x is: {}", x);
26 |     x = 6;
   |     ^^^^^ cannot assign twice to immutable variable
   |
help: consider making this binding mutable
   |
24 |     let mut x = 5;

使用mut以后运行正常并输出

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

👉使用下划线忽略未使用的变量

未使用的变量Rust 会给我们一个警告

let z=5;


  --> src\main.rs:24:9
   |
24 |     let z= 5;
   |         ^ help: if this is intentional, prefix it with an underscore: `_z`

可以使用下划线忽略这个未使用变量的警告

fn main() {
    let _z= 5;
}

👉变量解构

let 表达式不仅用于变量的绑定,还能进行复杂变量的解构,这里跟前端的JS的解构十分类似

fn main() {
    let (a, mut b): (bool,bool) = (true, false);
    // a = true,不可变; b = false,可变
    println!("a = {:?}, b = {:?}", a, b);

    b = true;
    assert_eq!(a, b);
}

// 这里assert_eq! 这个宏的作用如下
assert_eq!宏在测试失败时,会自动输出一条错误消息
这条消息包含了 a 和 b 的值,以及发生 panic 的位置

🍎 Rust 1.59版本后,在赋值语句的左式中使用元组、切片和结构体模式了

我们可以分别从几种结构之中进行解构赋值,从下面的赋值可以看出,无论采取哪种解构赋值均可


fn main() {
    let (a, b, c, d, e); // 声明变量但不进行初始化
    (a, b) = (1, 2); // 元组模式匹配
    [c, .., d, _] = [1, 2, 3, 4, 5]; // 数组模式匹配 // _ 代表匹配一个我们不关心的具体值
    Struct { e, .. } = Struct { e: 5 }; // 结构体模式匹配
    print!("{a}, {b}, {c}, {d}, {e}"); // 输出 1, 2, 1, 4, 5
    assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);
}

//输出 1, 2, 1, 4, 5

需要注意

  • 使用方式跟 let 保持一致,但是 let 会重新绑定,这里是对之前绑定的变量进行再赋值
  • 使用 += 的赋值语句还不支持解构式赋值

👉变量与常量差异

在rust之中我们声明变量常量如下

let声明变量,const声明常量且通常大写

(Rust 常量的命名约定是全部字母都使用大写,并使用下划线分隔单词,另外对数字字面量可插入下划线以提高可读性)

const MAX_USERS: u32 = 100; // 常量,不能改变
let mut current_users = 50; // 变量,初始值为 50

// 修改变量的值
current_users += 10; // 变为 60

// 你不能修改常量的值
// MAX_USERS = 200; // 编译错误

总结一下区别大致如下:

特性 变量(Variables) 常量(Constants)
可变性 默认不可变,使用 mut
可变更改值
不可变
生命周期 局部作用域内,超出作用域会销毁 在整个程序中存在
类型推导 可以推导类型,也可以显式声明 必须显式声明类型
计算时机 可以依赖运行时计算 必须在编译时计算
作用域 局部作用域,有限制 全局作用域,可在任意地方访问
实际应用 通常用于在程序中存储临时值,例如计数器、用户输入等。因为其可以在运行时进行修改,适合存储需要动态更新的值。 通常用于存储不变的值,例如程序配置、物理常数、应用中的限制值等。常量是编译时就确定的,因此在运行时不会有性能开销。

👉变量遮蔽

Rust 允许声明相同的变量名,后面声明的变量会遮蔽掉前面声明的

fn main() {
    let x = 5;
    // 在main函数的作用域内对之前的x进行遮蔽
    let x = x + 1;
    {
        // 在当前的花括号作用域内,对之前的x进行遮蔽
        let x = x * 2;
        println!("花括号内的x: {}", x);
    }

    println!("main函数内的x: {}", x);
}


//输出如下
花括号内的x: 12
main函数内的x: 6

关于这里Rust的变量遮蔽涉及到内存对象的再分配吗?个人理解

变量遮蔽只是创建了一个新的变量,并使用旧变量的值进行初始化
而不是分配新的内存空间

在 Rust 中,内存管理是自动的,当变量离开作用域时
它们使用的内存会被自动释放。

Rust中文圣经里面给我们的提示是说涉及到了内存对象的再分配,所以这里暂时还是个疑问,有理解的朋友可以发评论帮我解疑,为此我也建立了一个Rust学习群,帮助大家一起解答,私信我添加。

🍎原文是这样子的

和 mut 变量的使用是不同的
第二个 let 生成了完全不同的新变量,两个变量只是恰好拥有同样的名称,涉及一次内存对象的再分配 ,而 mut 声明的变量,可以修改同一个内存地址上的值
并不会发生内存对象的再分配,性能要更好。

🍎更新2025-06-24追加

应该是涉及到了内存对象的再分配,因为重新声明了

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。