Rust - 变量
不管学什么语言好像都得从变量开始,不过只需要懂得大概就可以了。
但在Rust里不先把变量研究明白后面根本无法进行…
变量绑定
变量赋值❌
变量绑定✔️
Rust中没有“赋值”一说,而是称为绑定。
int a = 3; //C中的变量赋值
a = 3; //python中的变量赋值
var a = 3; //JavaScript中的变量赋值
let foo = 3; //Rust中的变量绑定
这里就涉及 Rust 最核心的原则——所有权,简单来讲,任何内存对象都是有主人的,而且一般情况下完全属于它的主人,绑定就是把某个内存对象绑定给一个变量,让这个变量成为它的主人(在这种情况下,该对象之前的主人就会丧失对该对象的所有权)。
变量的可变性
Rust 的变量在默认情况下是不可变的。这是 Rust 语言的特性之一,有助于提升安全和性能。而通过 mut 关键字,即可以指定某个变量为可变的。
// 导入 io 模块,其中包含了处理输入输出的标准库
use std::io;fn main() {// 声明不可变变量 foo,开辟内存对象(值为1)并绑定给它let foo = 1; //编译器进行类型推断,这里推断出是int类型// 声明另一个不可变变量 bar// 开辟新的内存对象(并将 foo 绑定的值 1 拷贝进去),然后绑定给bar// 不可变变量在定义时(内存对象在开辟时)就需要进行值的绑定let bar = foo;// 检查 bar 绑定值是否为数字 1if bar == 1{ 这里的 println! 整体是一个宏,功能为打印一行文字println!("绑定成功")}
}
在上面的例子中,变量 foo和 bar 均为不可变变量,一旦为它绑定值,就不能再进行修改。
选择可变还是不可变,更多的还是取决于实际使用场景,例如不可变可以带来安全性,但是丧失了灵活性和性能,而可变变量最大的好处就是使用上的灵活性和性能上的提升。
// 导入 io 模块,其中包含了处理输入输出的标准库
use std::io;fn main() {println!("我要读取输入");println!("请输入:");// 使用 mut 关键字声明可变变量 rece,类型为 String// 并通过 String 类型内置的默认构造函数初始化为空字符串let mut rece = String::new(); //编译器从右值推断变量是string类型// 使用 io 模块下的 stdin().read_line 方法从标准输入读取一行内容到 rece 变量(绑定的内存)中// rece 需要是可变变量,(根本原因是 rece 绑定的内存需要可变)因为要按照用户输入内容进行修改// 使用 & 是因为此处传递的是参数变量绑定的内存而并非是内存中的值,这样子方便可以在程序的任何位置进行修改// 使用 expect 函数处理错误,如果发生错误则打印“无法读取行”io::stdin().read_line(&mut rece).expect("无法读取行");// 打印读取到的输入内容// {} 是占位符,输出的是后面变量的值。(多个{}就按顺序对应多个变量)println!("你输入的是:{}", rece);
}
在上面的例子中,rece 为一个可变变量,它的值可以进行修改。
这种做法是为了避免无法预期的错误发生在我们的变量上:一个变量往往被多处代码所使用,其中一部分代码假定该变量的值永远不会改变,而另外一部分代码却无情的改变了这个值,在实际开发过程中,这个错误是很难被发现的,特别是在多线程编程中。
变量未使用引起的错误
如果你创建了一个变量却不在任何地方使用它,Rust 通常会给你一个警告,因为这可能会是个 BUG。但是有时创建一个不会被使用的变量是有用的,比如你正在设计原型或刚刚开始一个项目。这时你希望告诉 Rust 不要警告未使用的变量,为此可以用下划线作为变量名的开头:
fn main() {//let foo;//let bar;//像上面这样如果变量定义了但不使用,就会发生警告let _foo;let _bar;//像上面这样,告诉编译器这两个变量是故意不使用的,就不会警告
}
变量遮蔽特性
Rust 允许声明相同的变量名,在后面声明的变量会“遮蔽”掉前面声明的,如下所示:
fn main() {let x = 5; //不可变变量,绑定的内存不可更改,内存的值不可更改。//假设绑定的内存对象为1号// 在main函数的作用域内对之前的x进行遮蔽let x = x + 1; //新的同名不可变变量进行遮蔽//绑定了新的内存对象,假设为2号,该内存对象中的值为(1号内存对象中存储的值+1)//这一行后面相同作用域的程序中,x都指代的是2号内存对象{// 在当前的花括号作用域内,对上面最近的x进行遮蔽let x = x * 2;println!("The value of x in the inner scope is: {}", x);}println!("The value of x is: {}", x);
}
这个程序首先将数值 5 绑定到 x,然后通过重复使用 let x = 来遮蔽之前的 x,并取原来的值加上 1,所以 x 的值变成了 6。第三个 let 语句同样遮蔽前面的 x,取之前的值并乘上 2,得到的 x 最终值为 12。当运行此程序,将输出以下内容:
The value of x in the inner scope is: 12
The value of x is: 6
注意: 这和 mut 声明可变变量的使用是不同的。第二个 let 生成了完全不同的新变量,因为它开辟了新的内存对象,两个变量只是恰好拥有同样的名称,但底层的内存对象是不同的。而 mut 声明的变量,可以修改同一个内存地址上的值,并不会产生新的内存对象。
变量遮蔽的用处在于,如果你在某个作用域内无需再使用之前的变量(在被遮蔽后,无法再访问到之前的同名变量),就可以重复的使用变量名字,而不用绞尽脑汁去想更多的名字。
变量遮蔽不仅可以作用于相同类型的变量,而且可以方便我们在改变变量类型的情况下仍然使用同样的名字:
//将输入的字符串转换成数字
fn main(){println!("输入一个大于0的数字");let mut guess = String::new();//guess为可变变量,绑定的内存不可更改,内存存储的值可更改//从这里往后的guess都是string类型io::stdin().read_line(&mut guess).expect("无法读取行");// 报错:string不能和int进行比较// if guess > 0 {// print!("数字大于0!")// }// 类型转换,绑定新的内存对象,内存类型是i32类型(int类型),可以进行比较// guess.trim().parse() 将字符串转换为数字,用guess绑定的新内存对象存储// 同名不同内存let guess:i32 = guess.trim().parse().expect("转换失败");//从这里往后的guess都是i32类型if guess > 0 {print!("数字大于0!");}
}
// 思考:为什么上面例子中的这句代码不能写成下面这样,进行类型推断?
let guess = guess.trim().parse().expect("转换失败");// 因为可变变量只有一块内存,内存类型是在声明时确定的,并且一旦声明,其类型就不能改变,类型推断也不行。
// guess已经绑定了string类型的内存对象
// 把一个数字存给string类型的内存对象是不允许的
// 错误原因是进行了错误类型赋值。
// 要改变可变变量的类型,就要靠(注明了类型的变量遮蔽)来实现。
不可变变量:内存不可改,内存的值不可改。
可变变量:内存不可改,内存的值可改。
相关文章:
Rust - 变量
不管学什么语言好像都得从变量开始,不过只需要懂得大概就可以了。 但在Rust里不先把变量研究明白后面根本无法进行… 变量绑定 变量赋值❌ 变量绑定✔️ Rust中没有“赋值”一说,而是称为绑定。 int a 3; //C中的变量赋值 a 3; //python中的…...
【Linux】压缩脚本、报警脚本
一、压缩搅拌 要求: 写一个脚本,完成如下功能 传递一个参数给脚本,此参数为gzip、bzip2或者xz三者之一; (1) 如果参数1的值为gzip,则使用tar和gzip归档压缩/etc目录至/backups目录中,并命名为/backups/etc…...
用Flask打造一个大模型智能问答WEB网站
目前已经有很多类似GPT的大模型开源,可以提供类似ChatGPT的智能问答功能。我也基于这些开源模型,用Flask来建立一个智能问答网站,可以方便用户建立自己的ChatGPT系统。 这个网站需要提供用户登录功能,对已登录的用户,可以在网站上提出问题,并由大模型处理后返回答案。演…...
学习python第三天
一.数据类型 1.获取数据类型 x 10 print(type(x))""" 输出 <class int> """2.复数类型(complex)详解 复数(Complex)是 Python 的内置类型,直接书写即可。换句话说,…...
(M)UNITY三段攻击制作
三段攻击逻辑 基本逻辑: 人物点击攻击按钮进入攻击状态(bool isAttack) 在攻击状态下, 一旦设置的触发器(trigger attack)被触发,设置的计数器(int combo)查看目前攻击…...
PHP的线程安全与非线程安全模式选哪个
曾经初学PHP的时候也很困惑对线程安全与非线程安全模式这块环境的选择,也未能理解其中意。近来无意中看到一个教程对线程安全(饿汉式),非线程安全(懒汉式)的描述,虽然觉得现在已经能够很明了透彻…...
asdf安装不同版本的nodejs和yarn和pnpm
安装asdf 安装nodejs nodejs版本 目前项目中常用的是14、16和18 安装插件 asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git asdf plugin-add yarn https://github.com/twuni/asdf-yarn.git可以查看获取所有的nodejs版本 asdf list all nodejs有很多找…...
Spring的事件监听机制
这里写自定义目录标题 1. 概述(重点)2. ApplicationEventMulticaster2.1 SimpleApplicationEventMulticaster2.2 AbstractApplicationEventMulticaster 3. ApplicationListener3.1 注册监听器3.2 自定义 4. SpringApplicationRunListeners 1. 概述&#…...
Zookeeper分布式命名服务实战
目录 分布式命名服务 分布式API目录 分布式节点的命名 分布式的ID生成器 分布式的ID生成器方案: 基于Zookeeper实现分布式ID生成器 基于Zookeeper实现SnowFlakeID算法 分布式命名服务 命名服务是为系统中的资源提供标识能力。ZooKeeper的命名服务主要是利用Z…...
DEV-C++ ege.h库 绘图教程(六)
一、前情回顾 DEV-C ege.h库 绘图教程(一) DEV-C ege.h库 绘图教程(二) DEV-C ege.h库 绘图教程(三) DEV-C ege.h库 绘图教程(四) DEV-C ege.h库 绘图教程(五)…...
MySQL原理(一)架构组成之物理文件组成
目录 一、日志文件 1、错误日志 Error Log 1.1、作用: 1.2、开启关闭: 1.3、使用 2、二进制日志 Binary Log & Binary Log Index 2.1、作用: 2.2、开启关闭: 2.3、Binlog还有一些附加选项参数 (1&#x…...
代码随想录算法训练营第三十七天 | 738.单调递增的数字、 968.监控二叉树
题目链接:738.单调递增的数字 文章讲解:代码随想录 738.单调递增的数字讲解 视频讲解:贪心算法,思路不难想,但代码不好写!LeetCode:738.单调自增的数字 思路和解法 题目: 当且仅当每个相邻位…...
【Django-ninja】django-ninja的hello world
django-ninja简介 Django Ninja是一个用于使用Django和Python 3.6类型提示构建API的Web框架。 主要特点: 易用性:旨在易于使用和直观。 高性能执行:由于Pydantic和异步支持,具有非常高的性能。 编码效率高:类型提…...
ArrayList集合初始化长度是多少,初始化的时候分配内存空间吗
ArrayList一旦初始化,在内存中就会分配空间吗 是的,当ArrayList在Java中初始化时,即使它没有添加任何元素,也会立即分配内存空间。具体来说,对于默认构造函数创建的ArrayList(即不指定初始容量)…...
C语言数组:从入门到进阶
前言: 在这篇博客中,我们将学习如何使用C语言数组的基本知识。数组是C语言中的一种重要数据结构,它允许我们存储一系列相同类型的数据。我们将讨论数组的定义、初始化、访问元素、遍历数组以及数组的应用场景。此外,我们还将通过…...
9.回文数
回文数 将整型转换为字符型反转前一半是否等于后一半将数字本身反转输入一个整数 x,如果 x是一个回文整数,返回 true;否则,返回 false 。 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 例如,121 是回文,而 123 不是。 将整型转换为字符型 反转…...
一分钟在SpringBoot项目中使用EMQ
先展示最终的结果: 生产者端: RestController RequiredArgsConstructor public class TestController {private final MqttProducer mqttProducer;GetMapping("/test")public String test() {User build User.builder().age(100).sex(1).address("世界潍坊渤…...
SOME/IP 协议介绍(七)传输 CAN 和 FlexRay 帧
SOME/IP 不应仅用于传输 CAN 或 FlexRay 帧。但是,消息 ID 空间需要在两种用例之间进行协调。 传输 CAN/FlexRay 应使用完整的 SOME/IP 标头。 AUTOSAR Socket-Adapter 使用消息 ID 和长度来构建所需的内部 PDU,但不会查看其他字段。因此,必…...
与数组相关经典面试题
𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - :来于“云”的“羽球人”。…...
数据结构与算法面试系列-02
1. 一个整数,它加上100后是一个完全平方数,加上168又是一个完全平方数,请问该数是多少? 程序分析:在10万以内判断,先将该数加上100后再开方,再将该数加上168后再开方,如果开方后的结果满足如下条件,即是结果。请看具体分析: 程序代码如下: package com.yoodb.uti…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
算法打卡第18天
从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7…...
