当前位置: 首页 > news >正文

Rust教程:How to Rust-变量

本文为第1篇

专栏简介

本专栏是优质Rust技术专栏,推荐精通一门技术栈的蟹友,不建议完全无计算机基础的同学

感谢Rust圣经开源社区的同学,为后来者提供了非常优秀的Rust学习资源

本文使用:

  • 操作系统macOS Sonoma 14 / Apple M1
  • 编译器:Rustc & Cargo

感谢一路相伴的朋友们,感谢你们的支持 ^ _ ^

Rust教程:How to Rust-变量


目录

专栏简介

更新记录

前言

变量命名

原生标识符

变量绑定

可变变量

下划线开头的变量

变量遮蔽

结语

快捷翻页

本文参考文献


更新记录

2024.03.10 发布文章


前言

变量怎么命名?关键字有哪些?命名个和关键字名字一样的变量或者函数行不?变量绑定是啥?变量为啥还要可变?声明完不想用行不行?变量可以起一样的名字吗?


变量命名

在命名方面,Rust与其他编程语言并无显著区别,但当我们为变量、函数或类型等构造命名时,需要遵循一些既定的命名规则。这些规则有助于增强代码的可读性和一致性,具体规则可以看这里,一般来说,对于类型级别的构造(如结构体、枚举和特征),Rust倾向于使用驼峰命名法(CamelCase),即每个单词的首字母大写,且没有下划线分隔。而对于值级别的构造(如变量和函数参数),则推荐使用蛇形命名法(snake_case),即所有字母小写,单词之间用下划线分隔。

Rust语言包含一些保留关键字,这些关键字具有特殊的语法意义,因此不能被用作变量名或函数名。以下是一些常见的Rust关键字及其用途:

  • 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 - 基于一个表达式的结果判断是否继续循环

 以下关键字无任何功能,但仍然由 Rust 保留以备将来的应用

  • abstract
  • async
  • await
  • become
  • box
  • do
  • final
  • macro
  • override
  • priv
  • try
  • typeof
  • unsized
  • virtual
  • yield

原生标识符

原生标识符是Rust语言提供的一种机制,它允许开发者使用通常无法直接作为变量名、函数名或类型名等标识符的关键字。通过在关键字前加上r#前缀,开发者就可以“借用”这些关键字作为自定义的标识符,从而避免命名冲突和限制

例如,match是Rust中的一个关键字,用于实现模式匹配。如果我们尝试将match用作一个函数的名字,如下所示:

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

编译器提示:

error: expected identifier, found keyword `match`--> src/main.rs:4:4|
4 | fn match(needle: &str, haystack: &str) -> bool {|    ^^^^^ expected identifier, found keyword

编译器会直接报错,因为match是保留关键字,不能被用作普通函数名。此时,原生标识符就派上了用场。我们可以使用r#前缀来将match作为函数名称使用,如下所示:

fn r#match() -> i64
{let variable = 1;variable
}fn main()
{let variable_output = r#match();println!("{}", variable_output)
}

通过这种方式,我们成功地规避了关键字带来的命名限制,实现了使用match作为函数名的目的。然而,需要注意的是,过度依赖原生标识符可能会导致代码可读性下降,因此在实践中应谨慎使用,并尽量使用更符合Rust命名习惯的替代方案


变量绑定

在JavaScript中,我们通常使用类似以下的方式为变量variable赋值:

var variable = "Hello World"

在上述代码中,计算机将等式右侧的字符串"hello world"赋值给变量variable。然而,在Rust中,我们采用了一种不同的方式来达到类似的效果:

let variable = "Hello World"

这个过程在Rust中被称为变量绑定,而不是赋值。那么,为什么Rust选择使用“绑定”这一术语而不是“赋值”呢?这背后涉及到Rust语言的核心原则——所有权。

简而言之,在Rust中,任何内存中的对象都有其特定的所有者,这个所有者完全掌控着该对象。当我们使用let关键字时,实际上是将一个内存对象绑定到一个变量上,这个变量随即成为该对象的所有者。与此同时,该对象之前的所有者(如果有的话)将失去对其的拥有权。这意味着在Rust中,一个对象在任何时刻只能有一个明确的拥有者。

这种所有权模型是Rust内存安全性的基石,它有助于防止诸如内存泄漏和悬挂指针等常见问题。通过明确绑定关系,Rust编译器能够跟踪哪些内存正在被使用,从而安全地进行清理和回收,确保程序的稳定运行。


可变变量

这个标题初听似乎有些出人意料,因为在大多数编程语言中,变量默认就是可变的。然而,在Rust中,情况恰恰相反。Rust中的变量默认是不可变的,包括我们之前提到的variable变量,其值一旦被绑定就不可再变。若需让变量可变,则需明确加上mut声明,类似下面这样

let mut variable = "Hello World"

这种语法可能初看起来有些多余,既然已经是变量了,为何还要额外声明它的可变性呢?

实际上,这种做法在大型项目中尤为重要。当一个变量被多处代码所引用时,有些代码可能期望该变量保持其原始值不变,而另一些代码则可能想要修改它。如果不加以明确声明,这种潜在的修改很难被及时发现,尤其是在多线程编程环境中,这种错误往往更为隐蔽和难以调试。因此,在Rust中通过mut关键字来明确变量的可变性,有助于提高代码的稳定性和可维护性。

这种规则让我们的代码逻辑变得非常清晰。当看到let关键字后面没有mut时,读者就能立即明白这个变量的值在后续代码中不会发生改变。而一旦看到mut,就像是给阅读代码的人打了“预防针”,提醒他们这个变量的值在后续可能会被更改


下划线开头的变量

如果你创建了一个变量却不在任何地方使用它,Rust通常会给你一个警告,因为这可能会是个 bug。但是有时创建一个不会被使用的变量是有用的,你希望能保留它,那么就可以在变量开头加上下划线(在C或C++中,下划线开头的变量是不被允许的,因为这可能是编译器使用的变量,但在Rust中,这是可以的)例如

fn main()
{let _variable_a = 5;let variable_b = 10;
}

在编译它时,Rust会提示

warning: unused variable: `variable_b`--> variable.rs:4:9|
4 |     let variable_b = 10;|         ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_variable_b`|= note: `#[warn(unused_variables)]` on by defaultwarning: 1 warning emitted

可以看到,两个变量都是只有声明,没有使用,但是编译器却独独给出了variable_b未被使用的警告,充分说明了_变量名前缀在这里发挥的作用

值得注意的是,这里编译器还很善意的给出了提示( Rust的编译器非常强大,这里的提示只是小意思 ): 将variable_b修改成 _variable_b即可


变量遮蔽

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

fn main()
{let variable = 5;let variable = variable + 1;{let variable = variable * 2;println!("{}", variable);}println!("{}", variable);
}

首先,数值 5 被绑定到变量variable。然后,通过使用let variable =重新声明并遮蔽了前面的variable,将其值更新为原值加 1,因此variable的值变为了 6。第三个 let 语句再次遮蔽了前面的variable,取用之前的值并乘以 2,最终variable的值变为 12。当运行此程序时,将输出以下内容:

$ ./shadowing
12
6

这种遮蔽机制与mut变量的使用有着显著的不同。mut允许我们在同一内存地址上修改变量的值,而不会发生内存对象的再分配,因此在性能上通常更优。而使用遮蔽时,每次let声明都会生成一个全新的变量,尽管它们恰好拥有相同的名称,但这实际上涉及到了内存对象的重新分配

变量遮蔽的用处在于,当我们在某个作用域内不再需要之前的变量(一旦被遮蔽,我们将无法再访问到之前的同名变量)时,可以重复使用变量名,这有助于避免绞尽脑汁去构思新的变量名,使代码更为简洁和清晰


结语

如果本文有任何问题欢迎在评论去指出,如果喜欢这篇文章,希望能点赞评论关注

如果你们身边有像你提起过这个领域的,或者希望可以和ta一起进步的,把这篇文章分享给ta吧

本文共4360字


快捷翻页

Rust教程:How to Rust-从开始之前到Hello World


本文参考文献

Rust圣经

文心一言

相关文章:

Rust教程:How to Rust-变量

本文为第1篇 专栏简介 本专栏是优质Rust技术专栏,推荐精通一门技术栈的蟹友,不建议完全无计算机基础的同学 感谢Rust圣经开源社区的同学,为后来者提供了非常优秀的Rust学习资源 本文使用: 操作系统macOS Sonoma 14 / Apple M…...

TCP/IP超全笔记 - TCP篇

TCP/IP超全笔记 - TCP篇 什么是 TCP TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接:一对一,先连接,再传输数据可靠交付:…...

MIT 6.858 计算机系统安全讲义 2014 秋季(一)

译者:飞龙 协议:CC BY-NC-SA 4.0 MIT 6.858 计算机系统安全笔记 2014 秋季 2014 年由Nickolai Zeldovich 教授和James Mickens 教授教授授课的 6.858 讲座笔记。这些讲座笔记略有修改,与 6.858 课程网站上发布的内容略有不同。 第1讲&#x…...

mybatis-plus整合spring boot极速入门

使用mybatis-plus整合spring boot,接下来我来操作一番。 一,创建spring boot工程 勾选下面的选项 紧接着,还有springboot和依赖我们需要选。 这样我们就创建好了我们的spring boot,项目。 简化目录结构: 我们发现&a…...

Kafka|处理 Kafka 消息重复的有效措施

文章目录 消息重复场景生产者端Kafka Broker消费者端 如何防止消息重复 消息重复是 Kafka 系统中另一个常见的问题,可能发生在生产者、Broker 或消费者三个方面。下面我们来讨论一些可能导致消息重复的场景以及如何处理。 消息重复场景 生产者端 重试机制导致消息…...

【C++】函数模板和类模板

目录 1.泛型编程 2.函数模板 2.1函数模板的定义格式 2.2函数模板的实例化 2.3函数模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 3.3模板的分离编译 1.泛型编程 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段…...

Echarts 配置项 series 中的 data 是多维度

文章目录 需求分析 需求 如下图数据格式所示,现要求按照该格式进行绘制折线图 分析 在绘制折线图时,通常我们的 series 中的 data 数据是这样的格式 option {title: {text: Stacked Area Chart},tooltip: {trigger: axis,axisPointer: {type: cross…...

快速了解Redis

Redis是什么? Redis是一个数据库,是一个跨平台的非关系型数据库,Redis完全开源,遵守BSD协议。它通过键值对(Key-Value)的形式存储数据。 与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库&am…...

1.2_2 OSI参考模型

文章目录 1.2_2 OSI参考模型一、概述(一)ISO/OSI参考模型是怎么来的?(二)ISO/OSI参考模型(三)ISO/OSI参考模型解释通信过程 二、各层功能及协议(一)应用层(第…...

CVPR 2024 | Modular Blind Video Quality Assessment:模块化无参视频质量评估

无参视频质量评估 (Blind Video Quality Assessment,BVQA) 在评估和改善各种视频平台并服务用户的观看体验方面发挥着关键作用。当前基于深度学习的模型主要以下采样/局部块采样的形式分析视频内容,而忽视了实际空域分辨率和时域帧率对视频质量的影响&am…...

C++指针(五)完结篇

个人主页:PingdiGuo_guo 收录专栏:C干货专栏 前言 相关文章:C指针(一)、C指针(二)、C指针(三)、C指针(四)万字图文详解! 本篇博客是介…...

使用registry镜像创建私有仓库

通过安装Docker后,Docker官网提供的registry镜像简单搭建一套本地私有仓库 1.通过registry镜像 ,做端口映射,创建一个容器,通过容器内的一个目录来创建私有仓库 并且将容器内仓库与本地路径做挂载 [rootnode1 ~]# docker run -d…...

前端发展史与优秀编程语言

前端开发是互联网技术领域中的一个重要分支,负责构建用户直接交互的网页和应用程序界面。随着互联网的发展,前端技术经历了多个阶段的演变,从最初的简单静态页面到如今的复杂交互式应用,不断推动着用户体验的提升和网页功能的丰富…...

利用SQL Server 进行报表统计的关键SQL语句与函数

在数据库应用中,报表统计是一项至关重要的任务,它为企业提供了数据洞察和决策支持。SQL Server作为一种强大的关系型数据库管理系统,提供了丰富的SQL语句和函数,可用于高效地进行报表统计。本文将介绍一些常用的SQL语句和函数&…...

【目标检测】旋转目标检测COCO格式标注转DOTAv1格式

DOTAv1数据集格式: imagesource:imagesource gsd:gsd x1, y1, x2, y2, x3, y3, x4, y4, category, difficult x1, y1, x2, y2, x3, y3, x4, y4, category, difficult ... imagesource: 图片来源 gsd: 分辨率 x1, y1, x2, y2, x3, y3, x4, y4:四边形的四…...

数据结构与算法:链式二叉树

上一篇文章我们结束了二叉树的顺序存储,本届内容我们来到二叉树的链式存储! 链式二叉树 1.链式二叉树的遍历1.1二叉树的前序,中序,后序遍历1.2 三种遍历方法代码实现 2. 获取相关个数2.1获取节点个数2.2获取叶节点个数2.3 获取树的…...

SpringMVC中接收参数总结

目录 一、引子 二、注解解析 RequestParam 一、要求形参名请求参数名,或者是请求实体类时(已有实体类),可以不需要加该注解 二、请求参数名!参数名时,需要写该注解RequestParam,其中 三、一名多值的情…...

使用 SPL 高效实现 Flink SLS Connector 下推

作者:潘伟龙(豁朗) 背景 日志服务 SLS 是云原生观测与分析平台,为 Log、Metric、Trace 等数据提供大规模、低成本、实时的平台化服务,基于日志服务的便捷的数据接入能力,可以将系统日志、业务日志等接入 …...

《日期类》的模拟实现

目录 前言: 头文件类与函数的定义Date.h 实现函数的Date.cpp 测试Test.cpp 运行结果: 前言: 我们在前面的两章初步学习认识了《类与对象》的概念,接下来我们将实现一个日期类,是我们的知识储备更加牢固。 头文件…...

RocketMQ架构详解

文章目录 概述RocketMQ架构rocketmq的工作流程Broker 高可用集群刷盘策略 概述 RocketMQ一个纯java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache的顶级开源项目…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...