青少年编程与数学 02-019 Rust 编程基础 03课题、变量与可变性
青少年编程与数学 02-019 Rust 编程基础 03课题、变量与可变性
- 一、使用多个文件(模块)
- 1. 创建包结构
- 2. 在 `main.rs` 中引入模块
- 示例:`main.rs`
- 3. 定义模块文件
- 示例:`module1.rs`
- 示例:`module2.rs`
- 4. 定义子模块
- 示例:`submodule/mod.rs`
- 示例:`submodule/subfunction.rs`
- 5. 使用模块
- 示例:`main.rs`
- 6. 包的结构和模块路径
- 7. 使用 `use` 语句简化路径
- 示例:`main.rs`
- 模块总结
- 二、常量
- 1. 常量的定义
- 示例:
- 2. 常量的特点
- 3. 常量的作用域
- 示例:
- 4. 常量的用途
- 示例:
- 5. 与变量的区别
- 6. 常量的限制
- 示例:
- 7. 常量的高级用法
- 示例:
- 常量总结
- 三、变量与可变性
- 1. 变量的声明与初始化
- 2. 默认不可变性
- 3. 可变性的作用
- 示例:不可变变量
- 示例:可变变量
- 4. 变量的绑定与阴影
- 5. 可变性与函数参数
- 6. 可变性与并发安全
- 示例:并发中的可变性
- 7. 示例合并
- 运行结果
- 8. 变量与可变性总结
- 总结
**摘要:**在 Rust 编程中,变量与可变性是核心概念之一。Rust 的设计哲学强调内存安全和并发安全,而变量的可变性规则是实现这些目标的重要机制。理解变量与可变性对于编写安全、高效的 Rust 代码至关重要。字面量、常量的应用虽然较为容易,但在编程过程也是必要知识。
**关键词:**常量、变量、可变性、安全、模块
一、使用多个文件(模块)
在 Rust 中,一个包(crate)可以包含多个源代码文件,而不仅仅是一个 main.rs
或 lib.rs
文件。通过合理组织代码结构,可以将功能拆分到多个文件中,提高代码的可读性和可维护性。以下是如何在一个包中使用多个源代码文件的方法。
1. 创建包结构
假设你正在创建一个二进制包(binary crate),其结构可以如下:
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs
│ ├── module1.rs
│ ├── module2.rs
│ └── submodule/
│ ├── mod.rs
│ └── subfunction.rs
2. 在 main.rs
中引入模块
在 Rust 中,模块(module)是组织代码的基本单元。你可以在 main.rs
中使用 mod
关键字引入其他源代码文件。
示例:main.rs
// 引入同一目录下的模块
mod module1;
mod module2;// 引入子模块
mod submodule;fn main() {// 使用模块中的函数module1::function1();module2::function2();// 使用子模块中的函数submodule::subfunction::function3();
}
3. 定义模块文件
每个模块文件对应一个 .rs
文件。在模块文件中,你可以定义函数、结构体、枚举等。
示例:module1.rs
pub fn function1() {println!("This is function1 from module1");
}
示例:module2.rs
pub fn function2() {println!("This is function2 from module2");
}
4. 定义子模块
子模块可以进一步组织代码。在子模块目录中,必须有一个 mod.rs
文件,它作为子模块的入口。
示例:submodule/mod.rs
// 引入子模块中的文件
mod subfunction;pub fn submodule_function() {println!("This is a function in submodule");
}// 重新导出子模块中的函数
pub use subfunction::function3;
示例:submodule/subfunction.rs
pub fn function3() {println!("This is function3 from subfunction");
}
5. 使用模块
在 main.rs
中,你可以通过模块路径访问定义在其他文件中的函数或类型。
示例:main.rs
mod module1;
mod module2;
mod submodule;fn main() {module1::function1(); // 调用 module1 中的函数module2::function2(); // 调用 module2 中的函数submodule::subfunction::function3(); // 调用 submodule/subfunction 中的函数
}
6. 包的结构和模块路径
Rust 使用文件系统结构来组织模块。模块路径由文件路径和 mod
关键字共同决定。以下是一些关键点:
- 每个
.rs
文件可以定义一个模块。 - 子模块目录需要包含一个
mod.rs
文件。 - 在父模块中使用
mod
关键字引入子模块。 - 使用
pub
关键字使模块、函数或类型对外可见。
7. 使用 use
语句简化路径
在代码中频繁使用长模块路径可能会使代码变得冗长。可以使用 use
语句将模块路径引入到当前作用域中。
示例:main.rs
mod module1;
mod module2;
mod submodule;// 引入模块中的函数
use module1::function1;
use module2::function2;
use submodule::subfunction::function3;fn main() {function1(); // 直接调用 function1function2(); // 直接调用 function2function3(); // 直接调用 function3
}
模块总结
通过合理组织代码结构,使用 mod
关键字引入模块,以及使用 use
语句简化路径,你可以在一个 Rust 包中使用多个源代码文件。这种方式不仅有助于代码的模块化,还可以提高代码的可读性和可维护性。
二、常量
在 Rust 中,常量是一种特殊的变量,它的值在程序运行期间不能被修改。常量在 Rust 中有其独特的用途和规则,以下是对 Rust 中常量的详细解析:
1. 常量的定义
在 Rust 中,常量使用 const
关键字定义。其基本语法如下:
const CONSTANT_NAME: Type = value;
CONSTANT_NAME
:常量的名称,通常使用大写字母和下划线来分隔单词,以符合 Rust 的命名约定。Type
:常量的类型,必须明确指定。value
:常量的值,必须是一个编译时可知的值。
示例:
const MAX_POINTS: u32 = 100_000;
在这个例子中,MAX_POINTS
是一个常量,类型为 u32
,值为 100_000
。
2. 常量的特点
- 不可变性:常量的值在定义后不能被修改。如果尝试修改常量的值,编译器会报错。
- 编译时常量:常量的值必须在编译时确定,不能依赖于运行时的值。
- 全局可访问性:常量在定义后可以在整个程序范围内访问,不受作用域的限制。
3. 常量的作用域
常量的作用域取决于其定义的位置:
- 全局常量:如果常量定义在模块的顶层,它可以在整个模块及其子模块中访问。
- 局部常量:如果常量定义在函数或模块的内部,它只能在该作用域内访问。
示例:
const GLOBAL_CONSTANT: i32 = 42;fn main() {const LOCAL_CONSTANT: i32 = 100;println!("Global constant: {}", GLOBAL_CONSTANT);println!("Local constant: {}", LOCAL_CONSTANT);
}
在这个例子中,GLOBAL_CONSTANT
是一个全局常量,可以在整个程序中访问;而 LOCAL_CONSTANT
是一个局部常量,只能在 main
函数中访问。
4. 常量的用途
常量在 Rust 中有多种用途,主要包括以下几点:
- 配置参数:用于定义程序的配置参数,这些参数在运行时不会改变。
- 数学常量:用于定义数学常量,如
PI
、E
等。 - 固定值:用于定义一些固定的值,如数组的大小、枚举的值等。
示例:
const PI: f64 = 3.141592653589793;
const ARRAY_SIZE: usize = 10;
5. 与变量的区别
- 可变性:变量可以被修改,而常量不能被修改。
- 存储位置:变量的值存储在内存中,而常量的值通常存储在代码段中。
- 作用域:变量的作用域通常受限于其定义的位置,而常量的作用域更广泛。
6. 常量的限制
- 值必须是编译时可知的:常量的值必须在编译时确定,不能依赖于运行时的值。
- 不能使用函数返回值:不能将函数的返回值赋值给常量,因为函数的返回值是运行时确定的。
示例:
const fn calculate() -> i32 {42
}const VALUE: i32 = calculate(); // 错误:不能在常量定义中调用函数
7. 常量的高级用法
- 常量泛型:Rust 支持在泛型中使用常量,这可以用于定义数组的大小或其他需要固定值的场景。
- 常量函数:Rust 允许定义常量函数,这些函数可以在编译时被调用。
示例:
const fn add(a: i32, b: i32) -> i32 {a + b
}const RESULT: i32 = add(2, 3);
常量总结
常量在 Rust 中是一种重要的特性,它用于定义在程序运行期间不可变的值。常量具有不可变性、编译时确定性以及全局可访问性等特点。通过合理使用常量,可以提高代码的可读性和安全性。
三、变量与可变性
1. 变量的声明与初始化
在 Rust 中,变量的声明使用 let
关键字。变量在声明时必须初始化,不能声明一个未初始化的变量。
let x = 5; // 声明一个变量 x,并初始化为 5
2. 默认不可变性
Rust 中的变量默认是不可变的(immutable)。一旦变量被赋值,其值就不能再被改变。这种设计可以防止意外修改变量值,从而减少错误。
let x = 5;
x = 6; // 错误:不能重新赋值给不可变变量
如果需要修改变量的值,必须在声明时明确指定变量为可变的(mutable),使用 mut
关键字。
let mut x = 5; // 声明一个可变变量 x
x = 6; // 正确:可以重新赋值
3. 可变性的作用
可变性(mutability)是 Rust 中一个重要的概念,它允许开发者明确控制变量的修改行为。通过限制变量的可变性,Rust 编译器可以在编译时检查潜在的错误,从而提高代码的安全性和可维护性。
示例:不可变变量
fn main() {let x = 5;println!("The value of x is: {}", x);// x = 6; // 错误:不能重新赋值给不可变变量println!("The value of x is: {}", x);
}
示例:可变变量
fn main() {let mut x = 5;println!("The value of x is: {}", x);x = 6;println!("The value of x is: {}", x);
}
4. 变量的绑定与阴影
Rust 允许使用相同的变量名重新声明变量,这种行为称为“阴影”(shadowing)。阴影可以用于在同一个作用域内重新绑定变量,而不会影响原始变量的不可变性。
pub fn f01() {let x = 5; // 第一次声明 xprintln!("The value of x is: {}", x);let x = x + 1; // 重新声明 x,创建一个新的变量println!("The value of x is: {}", x);let x = x * 2; // 再次重新声明 xprintln!("The value of x is: {}", x);
}
输出结果:
The value of x is: 5
The value of x is: 6
The value of x is: 12
在这个例子中,虽然变量名都是 x
,但每次使用 let
重新声明时,都会创建一个新的变量,而不会改变之前的变量值。
5. 可变性与函数参数
在 Rust 中,函数参数默认也是不可变的。如果需要在函数内部修改参数值,必须显式地将参数声明为可变的。
pub fn f02() {let mut x = 5;println!("The value of x is: {}", x);change(&mut x); // 传递可变引用println!("The value of x is: {}", x);
}fn change(x: &mut i32) {*x = 6; // 修改传入的可变引用
}
运行结果:
The value of x is: 5
The value of x is: 6
6. 可变性与并发安全
Rust 的可变性规则在并发编程中尤为重要。通过限制可变性,Rust 编译器可以确保在多线程环境中不会出现数据竞争问题。只有当变量被显式声明为可变时,才能对其进行修改,这使得 Rust 能够在编译时检查并发安全性。
示例:并发中的可变性
use std::thread;fn main() {let mut data = 5;let handle = thread::spawn(move || {data = 6; // 错误:data 不是可变的});handle.join().unwrap();
}
为了在多线程中安全地修改变量,可以使用 Arc
(原子引用计数)和 Mutex
(互斥锁)等工具来管理共享数据。
use std::sync::{Arc, Mutex};
use std::thread;pub fn f03() {let data = Arc::new(Mutex::new(5));let data_clone = Arc::clone(&data);let handle = thread::spawn(move || {let mut num = data_clone.lock().unwrap();*num = 6; // 正确:通过互斥锁修改数据});handle.join().unwrap();let num = data.lock().unwrap();println!("The value of data is: {}", *num);
}
运行结果:
The value of data is: 6
7. 示例合并
把上面三个示例代码放在不同模块中,使用一个主程序运行所有不同模块中的代码:
mod t01;
mod t02;
mod t03;fn main() {println!("t01::f01()运行结果:");t01::f01();println!("t02::f02()运行结果:");t02::f02();println!("t03::f03()运行结果:");t03::f03();
}
运行结果
t01::f01()运行结果:
The value of x is: 5
The value of x is: 6
The value of x is: 12
t02::f02()运行结果:
The value of x is: 5
The value of x is: 6
t03::f03()运行结果:
The value of data is: 6
8. 变量与可变性总结
- 变量默认不可变:Rust 中的变量默认是不可变的,需要使用
mut
关键字显式声明为可变。 - 阴影机制:可以通过重新声明变量来实现变量的“阴影”,而不会影响原始变量的不可变性。
- 可变性与函数参数:函数参数默认不可变,需要显式声明为可变。
- 可变性与并发安全:通过限制可变性,Rust 编译器可以在编译时检查并发安全性,避免数据竞争。
通过合理使用可变性规则,Rust 开发者可以编写出既安全又高效的代码。
总结
本文主要任务是讨论常量、变量及其可变性,根据需要先了解一Rust项目中,使用模块的概念,并按当前内容进行了示例操作,为后面的学习扫清障碍。
相关文章:
青少年编程与数学 02-019 Rust 编程基础 03课题、变量与可变性
青少年编程与数学 02-019 Rust 编程基础 03课题、变量与可变性 一、使用多个文件(模块)1. 创建包结构2. 在 main.rs 中引入模块示例:main.rs 3. 定义模块文件示例:module1.rs示例:module2.rs 4. 定义子模块示例&#x…...

S7-1500——零基础入门2、PLC的硬件架构
PLC的硬件架构 一,西门子PLC概述二,CPU介绍三,数字量模块介绍四,模拟量模块介绍五,其他模块介绍一,西门子PLC概述 本节主要内容 西门子PLC硬件架构,主要内容包括PLC概述、组成、功能及S7-1500 demo的组成与安装演示。 介绍了PLC的定义、功能、应用场合,以及与继电器控…...
前端面试宝典---webpack面试题
webpack 的 tree shaking 的原理 Webpack 的 Tree Shaking 过程主要包含以下步骤: 模块依赖分析:Webpack 首先构建一个完整的模块依赖图,确定每个模块之间的依赖关系。导出值分析:通过分析模块之间的 import 和 exportÿ…...

【PmHub后端篇】Skywalking:性能监控与分布式追踪的利器
在微服务架构日益普及的当下,对系统的性能监控和分布式追踪显得尤为重要。本文将详细介绍在 PmHub 项目中,如何使用 Skywalking 实现对系统的性能监控和分布式追踪,以及在这过程中的一些关键技术点和实践经验。 1 分布式链路追踪概述 在微服…...
Grafana v12.0 引入了多项新功能和改进
Grafana v12.0 引入了多项新功能和改进,旨在提升可观测性、仪表板管理和用户体验。以下是主要更新内容的总结: 🚀 主要新功能与改进 1. Git 同步仪表板(Git Sync) Grafana v12.0 支持将仪表板直接同步到 GitHub 仓库…...

利用“Flower”实现联邦机器学习的实战指南
一个很尴尬的现状就是我们用于训练 AI 模型的数据快要用完了。所以我们在大量的使用合成数据! 据估计,目前公开可用的高质量训练标记大约有 40 万亿到 90 万亿个,其中流行的 FineWeb 数据集包含 15 万亿个标记,仅限于英语。 作为…...
MongoDB使用x.509证书认证
文章目录 自定义证书生成CA证书生成服务器之间的证书生成集群证书生成用户证书 MongoDB配置java使用x.509证书连接MongoDBMongoShell使用证书连接 8.0版本的mongodb开启复制集,配置证书认证 自定义证书 生成CA证书 生成ca私钥: openssl genrsa -out ca…...
创始人 IP 的破局之道:从技术突围到生态重构的时代启示|创客匠人评述
在 2025 年的商业版图上,创始人 IP 正以前所未有的深度介入产业变革。当奥雅股份联合创始人李方悦在 “中国上市公司品牌价值榜” 发布会上,将 IP 赋能与城市更新大模型结合时,当马斯克在特斯拉财报电话会议上宣称 “未来属于自动驾驶和人形机…...
Gin 框架入门
Gin 框架入门 一、响应数据 JSON 响应 在 Web 开发中,JSON 是一种常用的数据交换格式。Gin 提供了简便的方法来响应 JSON 数据。 package mainimport ("github.com/gin-gonic/gin" )func main() {r : gin.Default()r.GET("/json", func(c *…...

【RabbitMQ】应用问题、仲裁队列(Raft算法)和HAProxy负载均衡
🔥个人主页: 中草药 🔥专栏:【中间件】企业级中间件剖析 一、幂等性保障 什么是幂等性? 幂等性是指对一个系统进行重复调用(相同参数),无论同一操作执行多少次,这些请求…...

软件设计师-错题笔记-系统开发与运行
1. 解析: A:模块是结构图的基本成分之一,用矩形表示 B:调用表示模块之间的调用关系,通过箭头等符号在结构图中体现 C:数据用于表示模块之间的传递的信息,在结构图中会涉及数据的流向等表示 …...
硬件设备基础
一、ARM9 内核中有多少个通用寄存器?其中 sp、lr、pc、cpsr、spsr 的作用是什么? 在 ARM9 内核中,寄存器组织包含 37 个 通用寄存器,其中,有 13 个通用目的寄存器(R0 - R12)。 S3C2440 是 ARM 架…...
[编程基础] PHP · 学习手册
🔥 《PHP 工程师修炼之路:从零构建系统化知识体系》 🔥 🛠️ 专栏简介: 这是一个以工业级开发标准打造的 PHP 全栈技术专栏,涵盖语法精粹、异步编程、Zend引擎原理、框架源码、高并发架构等全维度知识体系…...

C#简易Modbus从站仿真器
C#使用NModbus库,编写从站仿真器,支持Modbus TCP访问,支持多个从站地址和动态启用/停用从站(模拟离线),支持数据变化,可以很方便实现,最终效果如图所示。 项目采用.net framework 4.…...
Error parsing column 10 (YingShou=-99.5 - Double) dapper sqlite
在使用sqlite 调取 dapper的时候出现这个问题提示: 原因是 在 sqlite表中设定的字段类型是 decimel而在C#的字段属性也是decimel,结果解析F负数 小数的时候出现这个错误提示: 解决办法:使用默认的sqlite的字段类型来填入 REAL描述…...
Spring AI系列——使用大模型对文本进行内容总结归纳分析
一、技术原理与架构设计 1. 技术原理 本项目基于 Spring AI Alibaba 框架,结合 DashScope 大模型服务 实现文本内容的自动摘要和结构化输出。核心原理如下: 文档解析: 使用 TikaDocumentReader 解析上传的文件(如 PDF、Word 等&…...
【深度学习】目标检测算法大全
目录 一、R-CNN 1、R-CNN概述 2、R-CNN 模型总体流程 3、核心模块详解 (1)候选框生成(Selective Search) (2)深度特征提取与微调 2.1 特征提取 2.2 网络微调(Fine-tuning) …...
5.1.1 WPF中Command使用介绍
WPF 的命令系统是一种强大的输入处理机制,它比传统的事件处理更加灵活和可重用,特别适合 MVVM (Model, View, ViewModel)模式开发。 一、命令系统核心概念 1.命令系统基本元素: 命令(Command): 即ICommand类,使用最多的是RoutedCommand,也可以自己继承ICommand使用自定…...
excel大表导入数据库
前文介绍了数据量较小的excel表导入数据库的方法,在数据量较大的情况下就不太适合了,一个是因为mysql命令的执行串长度有限制,二是node-xlsx这个模块加载excel文件是整个文件全部加载到内存,在excel文件较大和可用内存受限的场景就…...
《让歌声跨越山海:Flutter借助Agora SDK实现高质量连麦合唱》
对于Flutter开发者而言,借助Agora SDK实现这一功能,不仅能为用户带来前所未有的社交体验,更是在激烈的市场竞争中脱颖而出的关键。 Agora SDK作为实时通信领域的佼佼者,拥有一系列令人瞩目的特性,使其成为实现高质量连…...
A* (AStar) 寻路
//调用工具类获取路线 let route AStarSearch.getRoute(start_point, end_point, this.mapFloor.map_point); map_point 是所有可走点的集合 import { _decorator, Component, Node, Prefab, instantiate, v3, Vec2 } from cc; import { oops } from "../../../../../e…...
单词短语0512
当然可以,下面是“opportunity”在考研英语中的常用意思和高频短语,采用大字体展示,便于记忆: ✅ opportunity 的考研常用意思: 👉 机会,良机 表示有利的时机或条件,尤指成功的可能…...

视觉-语言-动作模型:概念、进展、应用与挑战(下)
25年5月来自 Cornell 大学、香港科大和希腊 U Peloponnese 的论文“Vision-Language-Action Models: Concepts, Progress, Applications and Challenges”。 视觉-语言-动作 (VLA) 模型标志着人工智能的变革性进步,旨在将感知、自然语言理解和具体动作统一在一个计…...

一键解锁嵌入式UI开发——LVGL的“万能配方”
面对碎片化的嵌入式硬件生态,LVGL堪称开发者手中的万能配方。它通过统一API接口屏蔽底层差异,配合丰富的预置控件(如按钮、图表、滑动条)与动态渲染引擎,让工程师无需深入图形学原理,效率提升肉眼可见。 L…...
C# NX二次开发:宏录制实战讲解(第一讲)
今天要讲的是关于NX软件录制宏操作的一些案例。 下面讲如何在NX软件中复制Part体的录制宏。 NXOpen.Session theSession NXOpen.Session.GetSession(); NXOpen.Part workPart theSession.Parts.Work; NXOpen.Part displayPart theSession.Parts.Display; NXOpe…...
记录裁员后的半年前端求职经历
普通的人生终起波澜 去年下半年应该算是我毕业以来发生人生变故最多的一段时间。 先是 7 月份的时候发作了一次急性痛风,一个人在厦门,坐在床上路都走不了,那时候真的好想旁边能有个人能扶我去医院,真的是感受到 10 级的孤独。尝…...
Linux 文件查看|查找|压缩|解压 常用命令
cat 连接文件并打印到标准输出设备上 指令备注cat aaa.txt连接文件aaa并打印到标准输出设备上 more 以全屏幕的方式按页显示文本文件的内容 按Space键:显示文本的下一屏内容 按Enier键:只显示文本的下一行内容 指令备注more aaa.txt查看文件aaa le…...
什么是:Word2Vec + 余弦相似度
什么是:Word2Vec + 余弦相似度 目录 什么是:Word2Vec + 余弦相似度示例文本基于Word2Vec的文本向量化计算余弦相似度Word2Vec不是基于Transformer架构的Word2Vec是一种将单词转化为向量表示的模型,而Word2Vec + 余弦相似度则是一种利用Word2Vec得到的向量来计算文本相似性的…...

智慧城市综合运营管理系统Axure原型
这款Axure原型的设计理念紧紧围绕城市管理者的需求展开。它旨在打破传统城市管理中信息孤岛的局面,通过统一标准接入各类业务系统,实现城市运营管理信息资源的全面整合与共享。以城市管理者为中心,为其提供一个直观、便捷、高效的协同服务平台…...
[学习]RTKLib详解:convkml.c、convrnx.c与geoid.c
RTKLib详解: datum.c、download.c 与 lambda.c 本文是 RTKLlib详解 系列文章的一篇,目前该系列文章还在持续总结写作中,以发表的如下,有兴趣的可以翻阅。 [学习] RTKlib详解:功能、工具与源码结构解析 [学习]RTKLib详解ÿ…...