Rust 语言常见的一些概念(上)

news2025/7/27 20:45:59

目录

1、变量的可变性

常量

 隐藏

2、数据类型

2.1 标量类型

整型

浮点型

数值运算

布尔型

字符类型

复合类型

元组类型

数组类型


1、变量的可变性

变量默认是不可改变的(immutable)。这是 Rust 提供给你的众多优势之一,让你得以充分利用 Rust 提供的安全性和简单并发性来编写代码。不过,你仍然可以使用可变变量。

接下来我们测试一下,使用 cargo new variables命令在 projects 目录生成一个叫做 variables的新项目。

修改main.rs,内容如下所示:

fn main() {
    let v = 1;
    v = 2;
    println!("Hello, world! {v}");
}

在VSCode中打开,我们发现rust-analyzer插件有提示,无法修改不可变变量。

不过可变性也是非常有用的,可以用来更方便地编写代码。尽管变量默认是不可变的,你仍然可以在变量名前添加 mut 来使其可变,代码改成如下所示:

fn main() {
    let mut v = 1;
    println!("Hello, world! {v}");
    v = 2;
    println!("Hello, world! {v}");
}

常量

类似于不可变变量,常量 (constants) 是绑定到一个名称的不允许改变的值,不过常量与变量还是有一些区别。

首先,不允许对常量使用 mut。常量不光默认不可变,它总是不可变。声明常量使用 const 关键字而不是 let,并且必须声明值的类型。

把上面代码改成如下所示:

fn main() {
    const PI: f64 = 3.14159;
    println!("Hello, world! {PI}");
}

 隐藏

在同一作用域内,可以多次声明一个变量,可以用相同变量名称来隐藏一个变量,以及重复使用 let 关键字来多次隐藏,如下所示:

fn main() {
    let name = "zhangsan";
    let name = "lisi";
    println!("我的名字是:{name}");
    {
        let name = "wangwu";
        let name = "zhaoliu";
        println!("我的名字是:{name}");
    }
}

会打印对应的结果,但是重复定义的地方会有提示,说变量未引用,如果是有意为之的,建议加一个下划线的前缀。

隐藏与将变量标记为 mut 是有区别的。当不小心尝试对变量重新赋值时,如果没有使用 let 关键字,就会导致编译时错误。通过使用 let,我们可以用这个值进行一些计算,不过计算完之后变量仍然是不可变的。

mut 与隐藏的另一个区别是,当再次使用 let 时,实际上创建了一个新变量,我们可以改变值的类型,并且复用这个名字。例如,假设程序请求用户输入空格字符来说明希望在文本之间显示多少个空格,接下来我们想将输入存储成数字(多少个空格):

fn main() {
    let spaces = "zhangsan";
    let spaces = spaces.len();
    println!("长度是:{spaces}")
}

在编辑中可以看到同一个变量被赋值,对应的类型也改变了。

第一个 spaces 变量是字符串类型,第二个 spaces 变量是数字类型。隐藏使我们不必使用不同的名字,如果我们通过mut声明为可变变量,再看下会怎么样?

fn main() {
    let mut spaces = "zhangsan";
    spaces = spaces.len();
    println!("长度是:{spaces}");
}

这说明刚开始的时候,我们声明变量的类型已固定,我们不能改变变量的类型了。

2、数据类型

每一个值都属于某一个 数据类型data type),这告诉 Rust 它被指定为何种数据,以便明确数据处理方式。我们将看到两类数据类型子集:标量(scalar)和复合(compound)

使用 parse 将 String 转换为数字时,必须增加类型注解,像这样:

let guess:u32 = "100".parse().expect("");

如果没有对guess添加类型定义,会出现以下错误:

2.1 标量类型

标量scalar)类型代表一个单独的值。Rust 有四种基本的标量类型:整型、浮点型、布尔类型和字符类型。

整型

整数 是一个没有小数部分的数字。前面示例中使用过 u32 整数类型。该类型声明表明,它关联的值应该是一个占据 32 比特位的无符号整数(有符号整数类型以 i 开头而不是 u),以下表格展示了 Rust 内建的整数类型。

长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize

isize 和 usize 类型依赖运行程序的计算机架构:64 位架构上它们是 64 位的,32 位架构上它们是 32 位的。

注意:可以是多种数字类型的数字字面值允许使用类型后缀,例如 57u8 来指定类型,同时也允许使用 _ 做为分隔符以方便读数,例如1_000,它的值与你指定的 1000 相同。

数字字面值例子
Decimal (十进制)98_222
Hex (十六进制)0xff
Octal (八进制)0o77
Binary (二进制)0b1111_0000
Byte (单字节字符)(仅限于u8)b'A'

浮点型

Rust 也有两个原生的 浮点数floating-point numbers)类型,它们是带小数点的数字。Rust 的浮点数类型是 f32 和 f64,分别占 32 位和 64 位。默认类型是 f64,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高。所有的浮点型都是有符号的。

这是一个展示浮点数的实例:

浮点数采用 IEEE-754 标准表示。f32 是单精度浮点数,f64 是双精度浮点数。

数值运算

Rust 中的所有数字类型都支持基本数学运算:加法、减法、乘法、除法和取余。整数除法会向零舍入到最接近的整数。以下是一些示例:

fn main() {
    let plus = 2 + 3;
    let sub = 5 - 2;
    let mul = 2 * 3;
    let div = 3 /2;
    let rem = 3 % 2;
    println!("{plus} - {sub} - {mul} - {div} - {rem}") 
}

布尔型

Rust 中的布尔类型有两个可能的值:true 和 false。Rust 中的布尔类型使用 bool 表示。例如:

fn main() {
    let a = false;
    let b:bool = true;
    print!("{a} {b}")
}

字符类型

Rust 的 char 类型是语言中最原生的字母类型。下面是一些声明 char 值的例子:

fn main() {
    let a = 'A';
    let b:char = 'a';
    println!("{a} - {b}")
}

复合类型

复合类型可以将多个值组合成一个类型。Rust 有两个原生的复合类型:元组(tuple)和数组(array)。

元组类型

元组是一个将多个其他类型的值组合进一个复合类型的主要方式。元组长度固定:一旦声明,其长度不会增大或缩小。

我们使用包含在圆括号中的逗号分隔的值列表来创建一个元组。元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。这个例子中使用了可选的类型注解:

let tup: (char, f32, bool) = ('A', 3.2, true); 

tup 变量绑定到整个元组上,因为元组是一个单独的复合元素。为了从元组中获取单个值,可以使用模式匹配(pattern matching)来解构(destructure)元组值,像这样:

fn main() {
    let tup: (char, f32, bool) = ('A', 3.2, true); 
    let (x,y,z) = tup;
    println!("{x} {y} {z}") // A 3.2 true
}
数组类型

另一个包含多个值的方式是 数组array)。与元组不同,数组中的每个元素的类型必须相同。Rust 中的数组与一些其他语言中的数组不同,Rust 中的数组长度是固定的。

fn main() {
    let x = [1, 2, 3, 4, 5];
}

你还可以通过在方括号中指定初始值加分号再加元素个数的方式来创建一个每个元素都为相同值的数组:

fn main() {
    let a = [3; 5];
}

变量名为 a 的数组将包含 5 个元素,这些元素的值最初都将被设置为 3。这种写法与let a = [3,3,3,3,3]效果一样。

访问数组元素

fn main() {
    let x = [1, 2, 3, 4, 5];
    let y = x[0];
    let z = x[9];
    println!("{z}")
}

我们可以通过数组的索引去取值,跟js,ts语言取值一样。

当访问超过边界的索引时,会报一个运行时的错。

程序在索引操作中使用一个无效的值时导致 运行时 错误。程序带着错误信息退出,并且没有执行最后的 println! 语句。当尝试用索引访问一个元素时,Rust 会检查指定的索引是否小于数组的长度。如果索引超出了数组长度,Rust 会 panic,这是 Rust 术语,它用于程序因为错误而退出的情况。这种检查必须在运行时进行,特别是在这种情况下,因为编译器不可能知道用户在以后运行代码时将输入什么值。

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

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

相关文章

win32 读写UTF-8格式的文件的方法

1,写入数据 最开始是在写入数据前先写入三个字节 BYTE btHead[] { 0xEF,0xBB,0xBF }; ::WriteFile(hFile, btHead, 3, &dwWrite, 0); ::WriteFile(hFile, str, lstrlen(str)*sizeof(TCHAR), &dwWrite, 0);这样写入后文件样式为: 格式是UTF-8…

基于Python制作一个动物识别小程序

目录 引言研究背景目的与意义 动物识别技术概述基本原理图像处理与特征提取机器学习与深度学习方法 数据集与数据预处理数据收集与构建数据预处理步骤数据增强技术 特征提取与选择基础特征提取方法特征选择与降维 引言 研究背景 动物识别是计算机视觉和模式识别领域的重要研究…

《深入浅出OCR》实战:基于CRNN的文字识别

✨专栏介绍: 经过几个月的精心筹备,本作者推出全新系列《深入浅出OCR》专栏,对标最全OCR教程,具体章节如导图所示,将分别从OCR技术发展、方向、概念、算法、论文、数据集等各种角度展开详细介绍。 💙个人主页: GoAI |💚 公众号: GoAI的学习小屋 | 💛交流群: 7049325…

在python中加载tensorflow-probability模块和numpy模块

目录 操作步骤: 注意: 问题: 解决办法: 操作步骤: 在虚拟环境的文件夹中,找到Scripts文件夹,点击进去,找到地址栏,在地址栏中输入cmd,进入如下界面。 输…

国产数据库兼容过程中涉及的MySQL非严格模式

点击上方蓝字关注我 在国产数据库兼容适配过程中,经常遇到因源数据库是MySQL,迁移至其他国产数据库后,因MySQL端兼容模式有非严格模式,导致适配过程过程中需要做调整。那么,MySQL主要的非严格模式小结如下:…

约会杭州云栖2023:为了无法计算的价值一起努力

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师…

C++初阶 类和对象(上)

前言:C初阶系列,每一期博主都会使用简单朴素的语言将对应的知识分享给大家,争取让所有人都可以听懂,C初阶系列会持续更新,上学期间将不定时更新,但总会更的 目录 一、什么是面向对象编程 二、什么是类和如…

AST反混淆实战|变种ob混淆还原指南一

关注它,不迷路。 本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除! 1.需求 ob混淆是我们最常见的混淆代码,标准的混淆 可以用星…

如何读懂深度学习python项目,以`Multi-label learning from single positive label`为例

Paper : Multi-label learning from single positive label Code 先读一读README.md 可能有意想不到的收获; 实验环境设置要仔细看哦! 读论文 如何读论文,Readpaper经典十问 (可能在我博客里有写) How to read a …

【UE5】如何在UE5.1中创建级联粒子系统

1. 可以先新建一个actor蓝图,然后在该蓝图中添加一个“Cascade Particle System Component” 2. 在右侧的细节面板中,点击“模板”一项中的下拉框,然后点击“Cascade粒子系统(旧版)” 然后就可以选择在哪个路径下创建级…

Notepad++下载、使用

下载 https://notepad-plus-plus.org/downloads/ 安装 双击安装 选择安装路径 使用 在文件夹中搜索 文件类型可以根据需要设置 如 *.* 说明是所有文件类型; *.tar 说明是所有文件后缀是是tar的文件‘;

【Rust日报】2023-10-30 理解 Rust 中的生命周期

理解 Rust 中的生命周期 生命周期(Lifetime)是让 Rust 成为 Rust 的关键因素。 没有了生命周期,轻松的并发、直接的内存分配和整体的数据安全都是不可能的。 但是,生命周期也很难理解,这篇教程会帮助人们理解生命周期的…

【强化学习】13 —— Actor-Critic 算法

文章目录 REINFORCE 存在的问题Actor-CriticA2C: Advantageous Actor-Critic代码实践结果 参考 REINFORCE 存在的问题 基于片段式数据的任务 通常情况下,任务需要有终止状态,REINFORCE才能直接计算累计折扣奖励 低数据利用效率 实际中&#…

【Java】多线程案例(单例模式,阻塞队列,定时器,线程池)

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录 实现安全版本的单例模式饿汉模式类和对象的概念类对象类的静态成员与实例成员 懒汉模式如何保证…

C++设计模式_21_Iterator 迭代器(理解;面向对象的迭代器已过时;C++中使用泛型编程的方式实现)

Iterator 迭代器也是属于“数据结构”模式。GoF中面向对象的迭代器已经过时,C中目前使用泛型编程的方式实现,其他语言还在使用面向对象的迭代器。 文章目录 1. 动机(Motivation)2. 模式定义3. Iterator 迭代器代码分析4. 面向对象的迭代器与泛型编程实现…

一天写一个(前端、后端、全栈)个人简历项目(附详源码)

一、项目简介 此项目是用前端技术HTMLCSSjquery写的一个简单的个人简历项目模板,图片可点击放大查看,还可以直接下载你的word或者PDF的简历模板。 如果有需要的同学可以直接拿去使用,需自行填写个人的详细信息,发布,…

uniapp 开发微信小程序 v-bind给子组件传递函数,该函数中的this不是父组件的二是子组件的this

解决办法:子组件通过缓存子组件this然后,用bind改写this 这个方法因为定义了全局变量that 那么该变量就只能用一次,不然会有赋值覆盖的情况。 要么就弃用v-bind传入函数,改为emit传入自定义事件 [uniapp] uview(1.x) 二次封装u-navbar 导致…

程序开发设计原则

(图片来自网络) 单一职责 Single Responsibility Principle 不论是在设计类,接口还是方法,单一职责都会处处体现,单一职责的定义:我们把职责定义为系统变化的原因。所有在定 义类,接口&#xff…

CV2 将图片中某个点与中心点的角度变换成0-360度

众所周知,CV2中的坐标方向是这样的: 所以一般我们想计算图片中某个点P1(x1,y1)与中心点P0(x0,y0)的方向时,我们会先将y坐标翻上去,然后计算角度。即: p1_xint(x1) # p1_yint(y1)p0_xint(x0) #图像大小为512*512中心点坐标为25…

PO-提示json不能为空 not valid json at character 2 of ““““

问题描述: 调用第三方REST接口,提示提示json不能为空 not valid json at character 2 of """" 原因分析: 一般都是对方接收后出现错误没有处理,返回空值;有可能是他们映射有问题 解决方案&…