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

Rust学习笔记(二)|变量、函数与控制流

本篇文章包含的内容

  • 1 变量与常量
  • 2 类型
    • 2.1 标量类型
    • 2.2 复合类型
  • 3 函数
  • 4 控制流
    • 4.1 分支
    • 4.2 循环


1 变量与常量

在Rust中,使用let关键字声明一个变量,变量默认是不可变的。如果要声明可变变量,需要使用mut关键字将其声明为可变变量。

let x = 1;
x = 2;			// 默认不可变,非法
let x = 2;		// shadow,合法let mut y = 1;
y = 2;

声明常量需要使用const关键字,并且在声明时必须指明类型。它甚至可以声明在全局部位,命名需要满足一定的规则:字母全部大写,单词之间用下划线隔开。

const MAX_POINT : u32 = 100_000;

常量一定是不可变的,所以不需要mut关键字声明,但是它与默认不可变的let声明的变量有区别。它的赋值结果只能是常量表达式,不能是函数的返回值或者运行时才可以获得的值。

shadowing(隐藏)是Rust的一个重要特性,它允许新声明的变量的变量名替代旧变量。这在很大程度上提高了程序的可读性。被shadow前后的变量类型可以不同。

let spaces = "    ";			// str
let spaces = spaces.len();		// usize,这里返回 4

2 类型

2.1 标量类型

Rust中有四种标量类型(老四样):

  • 整数:默认i32
  • 浮点:默认f64
  • 布尔:只有两个值,truefalse,占一个字节。
  • 字符:Unicode标量值,占用4个字节,可以表示中日韩字符,emoji表情等。

整数类型具体可由下表表示。其中isizeusize由操作系统决定,如果操作系统是64位,则isize相当于i64usize相当于u64
请添加图片描述
整数的表示与C/C++类似,甚至可以添加下划线以提高可读性。例如10_00000xA00b1100_0011、甚至可以表示为byte类型(u8 only):b'A'。除了byte类型外,其他整数都可以使用类型后缀,例如57u8。如果整数溢出,Rust仅会在debug编译模式下panic(恐慌),而在release版本中程序不会panic。

2.2 复合类型

Rust语言中有两种基础的复合类型,即元组(Tuple)和数组。元组用小括号表示,数组用中括号表示。元组中的每一个元素可以是不同类型,而数组中的所有元素都必须是同一种类型。无论是元组还是数组,都需要显式声明他们的类型。

下面是一个使用元组的例子,可以临时声明一个新的元组,例如(x, y, z)来结构获取旧元组中的每一个成员(Rust会自动推断xyz的类型)。

fn main() {let tup : (i32, i64, u8) = (1, 2, 3);let (x, y, z) = tup;    // destructureprintln!("{}, {}, {}", x, y, z);println!("{}, {}, {}", tup.0, tup.1, tup.2)
}

使用下面的方法定义一个数组,可以显式地制定数组元素的类型,也可以让Rust编译器自动推断所需的数组类型。如果访问的数组索引超出了数组的范围,编译可能不会报错,但是运行时会导致程序panic。

fn main() {let a = [1, 2, 3, 4 , 5];let b: [i32; 5] = [1, 2, 3, 4, 5];let mouths = ["January","February","March","April","May","June","July","August","September","October","November","December"];let arr = [1; 3];   // let arr = [1, 1, 1];println!("{} {}", a[0], b[1]);
}

如果想让数据存放在stack(栈)内存而不是heap(堆)内存上,或者想要保证有固定数量的元素,则可以使用数组。数组是Stack上分配的单个块的内存。数组是定长的,而与之对应可变长度的数组称为Vector(向量)。如果在实际编程中不知道需要使用数组还是Vector,那么一般都需要使用Vector。

3 函数

Rust函数的命名规范采用snake_case规范,即全部小写,单词之间用下划线分开。Rust中的函数定义顺序无需尊循C/C++的习惯,即函数必须先声明再使用,在Rust中,可以将函数的定义放在函数使用之后。函数参数的类型必须指明。

fn main() {another_func(3);
}fn another_func(num: i32) {println!("Another function!");println!("the num is {}", num)
}

Rust是一个基于表达式的语言。任何一个函数体(语句块,由花括号括起)都由一系列语句组成,可选地,可以由一个表达式结束,函数的返回值就是表达式的值(表达式会产生一个计算值)

与表达式对应的概念称为语句,一个语句相当于一个命令,语句没有返回值(它返回一个空的Tuple)。函数的定义也是一个语句,所以它不能当作值赋值给变量(废话),这一点和C/C++有很大不同(笔者认为相当于修复了C/C++的一个bug?)。函数的定义是语句,但是调用函数(宏)是一个表达式。

let x = (let y = 6);		// 非法let y = {let x = 1;x + 2		// 不能加分号
};println!("the value of y is {}", y);	// 3

对于需要返回值的函数,在->符号后声明函数返回值的类型,但是不能为返回值命名。在Rust中,函数的返回值就是函数最后一个表达式的值,如果需要提前返回,则可以使用 return 关键字,并指定一个值

fn main() {let x = add_five(4);println!("{}", x);		// 9
}fn add_five(num: i32) -> i32 {num + 5// return num + 5;
}

4 控制流

4.1 分支

if表达式后需要添加一个条件,条件必须是bool类型(它不能是一个语句,这一点也与C/C++不同),与if相关联的代码称为分支(arm)。当程序中出现多个else if,则建议只用match语句重构代码。

fn main() {let x = 3;if x % 2 == 0 {println!("x can be devived by 2");} else if x % 3 == 0 {println!("x can be devived by 3");} else if x % 4 == 0 {println!("x can be devived by 4")}
}

if是一个表达式,所以它可以放在赋值号的右边。实现类似 ? : ;的效果。需要特别注意的是,ifelse后程序块的返回值的类型必须相同。

let condition = true;let number = if condition { 5 } else { 6 };		// 5

4.2 循环

Rust中有三种循环:loopwhilefor。其使用方法与C/C++和Python比较类似,但是Rust也提供了一些其他的语法糖。

loop表达式中可以使用break语句打断循环,并且break语句后可以添加表达式的值来指定loop表达式的返回值:

fn main() {let mut counter = 0;let result = loop {counter += 1;if counter == 10 {break counter * 2;}};println!("result: {}", result);		// 20
}

while循环使用较为简单,这里不赘述。

遍历集合元素一般使用for。Rust中同样存在迭代器的概念。注意,下面的例子中迭代器返回的是数组a的引用,如果直接写for element in a,则element将会被推断为i32类型,而不是&i32

fn main() {let a = [1, 2, 3, 4, 5];for element in a.iter() {println!("the value is {}", element);}
}

如果需要代码执行确定的次数,可以使用标准库提供的RangeRange可以通过开始数字和结束数字生成一个范围,但不包含结束数字。可以使用rev()方法获得反转的Range

fn main() {for number in (1..4).rev() {println!("{}!", number);}println!("LIFTOFF!");
}

请添加图片描述


  原创笔记,码字不易,欢迎点赞,收藏~ 如有谬误敬请在评论区不吝告知,感激不尽!博主将持续更新有关嵌入式开发、FPGA方面的学习笔记。


http://www.dtcms.com/a/327213.html

相关文章:

  • 【七指共振擒牛战法】副图+选股指标——多维度捕捉主升浪的量化交易利器
  • 智慧校园|智慧校园管理小程序|基于微信小程序的智慧校园管理系统设计与实现(源码+数据库+文档)
  • [Robotics_py] 定位滤波器 | 预测与更新 | 扩展卡尔曼滤波器(`EKF`)
  • Linux操作系统应用软件编程——标准IO
  • Java Stream ReduceOps
  • 负载均衡详解
  • 小程序排名优化:用户行为数据背后的提升密码
  • PostgreSQL 范围、空间唯一性约束
  • 「ECG信号处理——(23)基于ECG和PPG信号的血压预测」2025年8月12日
  • SQL 生成日期与产品的所有组合:CROSS JOIN(笛卡尔积)
  • Linux 系统运维、网络、SQL Server常用命令
  • 机器学习 [白板推导](九)[变分推断]
  • DRAM、SRAM、NAND Flash、NOR Flash、EEPROM、MRAM存储器你分得清吗?
  • 用pom文件从nexus3拉依赖,无法拉取的一个问题
  • 逻辑删除 vs 物理删除:MyBatis-Plus 实现指南与实践
  • 可泛化逻辑推理Python编程作为医疗AI发展方向研究
  • 关于数据库的restful api接口工具SqlRest的使用
  • 如何在 Ubuntu 24.04 LTS Linux 中安装 JSON Server
  • 2025年国赛新规解读:8-12最新发布文件
  • 初识数据结构——优先级队列(堆!堆!堆!)
  • 偶遇冰狐智能辅助的录音
  • Python初学者笔记第二十四期 -- (面向对象编程)
  • 教程 | 用Parasoft SOAtest实现高效CI回归测试
  • 从零到一的 Python CI/CD 实战指南:用 GitHub Actions 与 Jenkins 打造稳定、可持续交付的工程力
  • 下一代防火墙技术
  • 【ad-hoc 最小生成树 构造】P8957 「CGOI-3」巫泡弹弹乐|普及+
  • 【Redis在智能健身镜中的作用:运动指导与用户数据同步】
  • 计算机网络摘星题库800题笔记 第6章 应用层
  • 使用正则中的sub实现获取我们匹配的字符串,然后追加指定字符
  • 计算机网络---防火墙(Firewall)