Rust语言入门教程(二) - 变量与作用域

news2024/11/17 5:20:32

变量与作用域

变量的声明与初始化

Rust的基本语法格式如下:

fn main(){
	let bunnies = 2;
}

语句以分号结尾,用花括号包含语句块。 Rust的语法其实借鉴了很多其他的语言,比如C语言和Python, 所以变量定义的格式看起来也跟很多我们熟悉的其他语言相似。Rust中,使用let关键字声明一个变量。在上面的例子中, 我们声明了一个变量bunnies, 并且初始化了它的值为2.

Rust是一种强类型的语言,那么在上面的语句中,哪里标注了这个变量的类型呢?在Rust编程中,如果Rust能准确的识别这个变量的类型,那么我们不需要显式的标注变量的类型,也不需要像C#那样标注一个auto表示它的类型是自动识别的。

如果需要显式的标注一个变量的类型,可以像下面的例子一样做, 在变量名后加个: , 后面再写上变量的类型,如下,i32代表有符号的32位整型。

fn main(){
	let bunnies: i32 = 2;
}

与python类似,rust也可以在一行语句中定义多个变量。如下例子便可以在一行代码中为两个变量初始化:

fn main(){
	let (bunnies, carrots) = (8, 50);
}

变量不可变

在Rust中,变量默认其实是不可变的,也就是说,一旦对一个变量赋值以后,其值默认是不可被修改的。这一特点与大多数的其他编程语言都不同,其他编程语言的变量默认是随时可以被重新赋值的。那为什么Rust要将变量设置为默认不可变的呢?这就要提到上一章中我们提到的Rust的三个特性了:

  • 内存安全: 如果变量在运行过程中始终不变,这可以避免很多bug的发生,变量不可变这一设计,极大的提高了Rust的内存安全特性。
  • 无畏并发: 不变的变量,可以被多个线程在不加锁的情况下共享,这也使得Rust的并发更安全可靠。
  • 高性能: 不变的变量,使得编译器可以对其进行额外的优化,从而提高了代码的执行速度,提高了程序运行性能。

但是不得不承认我们在编程中一定会遇到需要修改变量的需求, 如果我们直接修改变量的值,编译便会报错,例如下面的代码:

fn main(){
	let bunnies: i32 = 2;
	bunnies = 3;   // Error!
}

如果运行上面的代码,将会得到下面的报错,可以看到,报错中非常明确的指出了代码的问题所在,并且还指出了修改建议, 在报错的最上面,给出了错误的描述,也就是:不能对不可变变量进行二次赋值。在报错中,也指出了错误所在的位置,第3行第5列。接下来还对整个错误的上下文进行了说明,告诉我们在第2行的时候对变量bunnies已经赋值,然后再第3行再次对不可变变量bunnies进行了赋值,因此报错。接着还提出了修改建议,让我们在第2行的变量名前面加上mut, 使其成为一个可变变量,也许能修复这个问题。在最后一行,如果上面的提示还不能解决问题,还可以运行rustc --explain e0384来查看错误的完整描述。
请添加图片描述
按照错误提示,我们将代码修改后如下便可以成功运行了:

fn main(){
	let mut bunnies: i32 = 2;
	bunnies = 3;   // Error!
}

常量

在Rust中,常量(constant)其实也属于变量的一种, 相比普通的不可变变量,它更加的不可变。定义一个常量包含以下四个关键步骤:

  • const而不是let声明;
  • 变量名格式为全大写字母加下划线分隔;
  • 必须声明变量类型;
  • 常量的值必须时编译时可确定值的表达式;

下面是普通变量和常量声明的对比:

let wrap_factor = ask_scotty();  // 变量
const WRAP_FACTOR: f64 = 9.9;    // 常量

定义一个常量比变量麻烦很多,那为什么还要用常量呢?

  • 常量可以在函数作用域外或者模块外进行定义,而在任意的地方使用;
  • 常量会在编译时被静态的写入可执行文件,使得运行速度很快;
  • Rust官方在每个发布版本中都对const类型增加了越来越多的功能和优化,在可以使用const的地方,使用const是一个好的选择;

作用域

每个变量都有各自的作用域,只有在变量的作用域中,变量才能被使用。代码的作用域通常是从变量被创建的地方开始,到变量所在的代码块结束, 在这个范围中的子代码块中,变量仍然是可以被访问的。

注: 代码块是一组被花括号包含的语句

fn main() {
    let x = 5;
    {
        let y = 99;
        println!("x = {}, y = {}", x, y);
    }
    println!("x = {}, y = {}", x, y); // Error!
}

在上面的代码中, 变量xmain函数的代码块中被定义,其中定义了一个子代码块,在子代码块中定义了一个变量y, 在子代码块中,xy都可以被访问, 在子代码块结束时, y立刻被销毁(Rust中没有任何的垃圾回收器,变量总是在离开作用域后被立即销毁),因此第二个println!语句不能访问变量y而发生错误。

然而我们不用担心这会在运行时发生bug, 因为这种错误会在编译时就被暴露出来。
请添加图片描述

变量隐藏

Rust中,也存在变量隐藏的现象

fn main() {
    let x = 5;
    {
        let x = 99;
        println!("x = {}", x);
    }
    println!("x = {}", x); // Error!
}

运行结果应该如下:

x = 99
x = 5

在上述代码中我们在子代码块外部定义了一个变量x并赋值为5, 在子代码块中,x的值被覆盖,为内层代码块中的值99。当离开了内层代码块后,内层的变量x被销毁, x的值又变回了外层代码块中的5.

再来看一个例子:

fn main() {
	let mut x = 5; // x is mutable
	let x = x;     // x is now immutable
}

这个例子中,第一个x被隐藏了,这其实相当于重新声明并初始化了x这个变量,在编译过程中, Rust甚至能识别到这种情形并优化执行的过程,并不会真的先定义一个可变的x, 再用一个新的x去覆盖它,而是直接定义一个不可变的变量x并为其赋值为5.

再看一个例子:

fn main() {
    let meme = "More cowbell!";
    let meme = make_image(meme);
}

在上述代码中, 变量meme甚至能被改变类型(从字符串变成了图片)。

变量与内存安全

在Rust中,在使用一个变量前,必须确保这个变量被初始化。

情景A

fn main() {
    let enigma: i32;
    println!("{}", enigma);  // Error!
}

请添加图片描述
可以看到,报错提示我们,变量虽然被声明了,但是没有被初始化。

情景B

fn main() {
    let enigma: i32;
    if true{
		enigma = 42;
	}
    println!("{}", enigma);  // Error!
}

请添加图片描述
即时是在一个恒为真的判断语句中为变量进行了初始化,编译器仍会报错, 因为判断语句只有在运行时才能被判别最终的结果,因此在编译时没办法确保该变量一定会被初始化。

为了保证变量一定被初始化,可以将上述代码改为如下:

fn main() {
    let enigma: i32;
    if true{
		enigma = 42;
	} else {
		enigma = 7;
	}
    println!("{}", enigma);  // Error!
}

如果在C语言中使用了一个未初始化的变量会出现什么现象呢,如下代码:

include <stdio.h>
int main(){
	int enigma;
	printf("%d\n", enigma);
}

这将不会导致编译报错,程序可以正常运行,但是会输出一个不可预测的结果,因为声明变量后, C语言就会在内存分配一个地址,而这个内存地址中存储的是什么数据,我们不得而知,它可能是任何东西。

小结

本章介绍了Rust中变量的种类,声明与赋值方式,以及变量的作用域和隐藏特性。下一章将介绍Rust的函数及模块系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1242732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中期财报解读:内地业务增长失速,维他奶还能做回豆奶一哥吗?

维他奶虽然起源于中国香港&#xff0c;但却是不少内地人的儿时回忆。 这与维他奶的业务布局侧重点有关&#xff0c;中国内地一直是维他奶最重要的市场。11月21日&#xff0c;维他奶公布了截至2023年9月30日止6个月的2024财年中期业绩。财报显示&#xff0c;维他奶业务构成中&a…

基于框架的线性回归

线性回归是机器学习中最简单和最常用的回归方法之一。它建立了自变量和因变量之间的线性关系&#xff0c;并通过拟合一条直线或超平面来预测和分析数据。 基于框架的线性回归是构建线性回归模型的一种常见方法&#xff0c;它利用现有的机器学习框架来实现线性回归模型的建立、…

解决错误0x80071ac3的问题,错误代码0x80071ac3的原因

在使用电脑的过程中可能会出现错误0x80071ac3的代码问题&#xff0c;一旦出现这样的问题解决起来可能会有点麻烦&#xff0c;其实这个错误是和磁盘的问题相关&#xff0c;可以将电脑重启尝试能否解决错误0x80071ac3问题&#xff0c;如果依然不能解决问题的话&#xff0c;那么大…

每日一题:LeetCode-105.从前序遍历与中序遍历构造二叉树

每日一题系列&#xff08;day 02&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

电动机保护方式

3.3.1、电动机温度保护 温度保护是利用安装在电动机内部的温度继电器或变换器来实现的。当电动机达到一定温度时继电器动作&#xff0c;通过控制电路断开电动机的主电路。对于单相小容量电动机&#xff0c;可以用继电器直接断开动力电路。 根据温度传感器的不同可以分为&…

Transformer ZOOs:transformer在不同领域的应用

Natural Language Processing Transformer:Attention is all you need URL(46589)2017.6 提出Attention机制可以替代卷积框架。引入Position Encoding&#xff0c;用来为序列添加前后文关系。注意力机制中包含了全局信息自注意力机制在建模序列数据中的长期依赖关系方面表现出…

permission is only granted to system apps 权限错误提示处理

permission is only granted to system apps 消除清单文件中的权限Permission is only granted to system apps 错误 在manifest文件中我们注册一些权限&#xff0c;当我们用到某些权限是会有一个错误提示&#xff1a;Permission is only granted to system apps&#xff0c;该…

IDEA的插件市场无法打开,无法连接到https://plugins.jetbrains.com/

1&#xff1a;网上搜到的&#xff1a; 在这里测试https://plugins.jetbrains.com/ 能否连接到&#xff0c;可以的话就成功&#xff0c;但是我一直失败&#xff0c;网络配置与防火墙也没问题。 2&#xff1a;我成功的方法&#xff1a; 把这个勾取消再测试&#xff0c;成功&…

创建文件夹的shell脚本

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 很简单&#xff0c;先判断文件夹是否存在&#xff0c;不存在则创建。具体如下&#xff1a; #!/bin/bash # 判断文件夹是否存在 if [ ! -d "$folder…

nn.linear()的用法

https://blog.csdn.net/zhaohongfei_358/article/details/122797190

如何使用ArcGIS Pro制作一张陆地和海洋对调后图

你是否有想过如果海洋和陆地对调一下——陆地变海洋&#xff0c;海洋变陆地后的世界地图会是什么样子&#xff0c;对于这个大胆的想法&#xff0c;我们可以通过ArcGIS Pro来制作地图&#xff0c;这里为大家介绍一下制作方法&#xff0c;希望能对你有所帮助。 数据来源 本教程…

经常喝羊奶,羊大师告诉你会有何不同

经常喝羊奶&#xff0c;羊大师告诉你会有何不同 羊奶&#xff0c;与人们日常饮用的牛奶相比&#xff0c;一直都没有得到足够的关注。然而&#xff0c;羊奶在一些特定方面却具有独特的优势。它不仅具有丰富的营养价值&#xff0c;还有助于提升人体的健康水平。本文小编羊大师将…

如何正确接入API接口通过淘宝商品ID和sku ID获取到淘宝商品SKU信息接口,可获取sku价格,sku销量,sku图片及sku库存参数等

接入API接口的正确方式可能因API的具体要求而有所不同&#xff0c;但一般来说&#xff0c;以下是一些通用的步骤&#xff1a; 获取API文档&#xff1a;API文档通常包括API的请求方式、请求参数、响应格式等信息。您需要仔细阅读文档&#xff0c;了解API的具体要求和使用方式。…

苹果怎么关闭悬浮球?让我来解答您的疑惑!

悬浮球是苹果设备上的一种可进行自定义的快捷操作功能&#xff0c;它可以位于手机屏幕的任意位置&#xff0c;以浮动的方式显示。然而&#xff0c;有时候悬浮球对某些朋友来说可能会变得多余&#xff0c;那么苹果怎么关闭悬浮球呢&#xff1f;接下来&#xff0c;小编将为大家揭…

ATFX汇市:11月美联储会议纪要提振美指,但中期跌势或将延续

ATFX汇市&#xff1a;11月21日公布的11月美联储利率决议会议纪要提到&#xff1a;过去一年通胀有所缓和&#xff0c;但目前通胀仍然高得令人无法接受&#xff0c;远高于委员会 2% 的长期目标&#xff1b;在消费者支出激增的推动下&#xff0c;第三季度实际 GDP 出人意料地强劲增…

maxwell采集数据到kafka报错

问题&#xff1a; 启动maxwell后出现数据更新后就出现以下报错。 13:29:14,727 ERROR MaxwellKafkaProducer - TimeoutException Position[BinlogPosition[binlog.000002:12215591], lastHeartbeat1700717043797] -- maxWellData: medical:consultation:[(id,212)] 13:29:14,7…

教育机构拒绝“数据陷阱”,群硕将英孚新一代教学管理系统搬上桌

为什么小机构年年担心招生不够&#xff0c;英孚却令学生家长趋之若鹜&#xff1f; 区别就在教学管理方式。为了更好地管理分布全球的校区、学生和老师&#xff0c;英孚应用了一套教学管理系统&#xff0c;帮助学校管理学员&#xff0c;帮老师智慧排课&#xff0c;帮助家长记录…

《实现领域驱动设计》笔记——上下文映射图

一个项目的上下文映射图可以用方式来表示。比较容易的一种是画一个简单的框图表示两个或多个限界上下文之间的映射关系。该框图表示了不同的限界上下文在解决方案空间中是如何通过集成相互关联的。另一种更详细的方式是通过限界上下文集成的源代码实现来表示。 上下文映射图为什…

section header

section header table 是一个section header的集合&#xff0c;每个section header是一个描述section的结构体。在同一个ELF文件中&#xff0c;每个section header大小是相同的。 每个section都有一个section header描述它&#xff0c;但是一个section header可能在文件中没有…

小白也看的懂的爬取视频操作

1.获取一段视频 可以直接从抖音下&#xff0c;也可以从b站上爬取&#xff08;注意法律谢谢&#xff09; 保护原创 b站的视频 直接复制网址链接到哔哩哔哩(bilibili)视频解析下载 - 保存B站视频到手机、电脑 去就好了&#xff0c;