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

Rust 学习笔记 - 流程控制 与 Range 类型

前言

任何一门编程语言几乎都脱离不了:变量、基本类型、函数、注释、循环、条件判断,这是一门编程语言的语法基础,只有当掌握这些基础语法及概念才能更好的学习 Rust。

条件判断

if 表达式

if 语句在其他语言中很常见,这里不再多做解释,看注释即可。

// 判断 n 是否小于 0
if n < 0 {// 当 n 小于 0 时执行这句print!("{} 是负数", n);
} else {// 否则执行这句print!("{} 是 0", n);
}

if 表达式也支持 if...else if...else 语句:

// 判断是否满足 if 条件1
if condition1 {// ...
} else if condition2 { // 当不满足 条件1 时,判断是否满足条件2// ...
} else { // 条件1 和 条件2 都不满足时// ...
}

在 Rust 中,没有像其他语言那样的三元表达式(三目运算符),但是在 Rust if 是一个表达式,这意味着可以在 let 语句中使用它来对变量进行条件赋值,从而达到类似三元表达式的效果。

let condition = true;// number 的类型必须明确,因此两个分支的返回值类型必须一致
let number = if condition { 5 } else { 6 };
println!("The value of number is: {}", number);

模式匹配(match 表达式)

虽然严格来说 match 并不是条件判断,但它常作为 Rust 的条件控制结构,其功能类似于其他语言中的 switch / case 语句。match 针对一个值执行模式匹配,并根据匹配到的模式执行相应的代码。

let value = some_val();match value {1 => println!("one"),2 => println!("two"),3 => println!("three"),_ => println!("anything"), // _ 类似于其他语言中的 default,用来匹配所有其它情况
}

match 匹配必须是穷尽的(exhaustive),也就是说所有可能的值都必须被考虑。使用 _ 模式可以捕捉所有未显式处理的值。

match 守卫(match guards)允许你为同一个 match 分支添加额外的条件判断,这样就可以基于值的属性做更精细的控制。

match some_val {val if val < 5 => println!("less than five"),val => println!("{}", val),
}

循环语句

loop 循环

loop 关键字创建了一个无限循环,它会不断地重复代码块,直到明确地通过 break 关键字退出循环。

let mut counter = 0;
loop {counter += 1;if counter == 10 {break;}
};

loop 也能返回一个值,这个值是在 break 后跟着的表达式。

let mut counter = 0;
let result = loop {counter += 1;if counter == 10 {break counter * 2; // 当 counter 达到 10 时退出循环,并返回 counter 的两倍}
};
println!("The result is {}", result); // 输出:The result is 20

while 循环

while 循环在循环的每次迭代开始前检查条件表达式,只有当条件为真时才会执行循环体。如果条件为假,则退出循环。

let mut number = 3;
while number != 0 {println!("{}", number);number -= 1;
}

和其他语言不一样在,Rust 中没有 do...while 语句,如果想要实现类似的效果可以通过 loop + if 模拟。

let mut count = 0;loop {count += 1;println!("这是第 {} 次迭代", count);// 判断条件,如果条件不满足,则退出循环if count >= 10 {break;}
}

for 循环

for 循环是开发中使用最频繁的循环,尤其是需要迭代一个序列或迭代器时。对于集合中的每个元素,它都会执行一次循环体。for 循环更加安全和高效,而且它不会产生越界的风险。

let a = [10, 20, 30, 40, 50];for element in a.iter() {println!("the value is: {}", element);
}

for 语句的特点

Rust 语言中的 for 循环不支持传统的 C/C++ 风格的 for (initialization; condition; update) 循环。在 Rust 中,for 循环被设计成基于迭代器的,这意味着它是用来遍历迭代器中的元素。之所以这样设计,是为了更安全和直接地处理集合中的元素,而不需要像在 C/C++ 中那样手动管理索引。

如果你想要执行类似于 for (int i = 0; i < 10; i++) 的循环,Rust 提供了一个 Range 类型,可以通过这个类型的 .. 或 ..=(包含上界)运算符来创建。

Rust 的 for 循环进行迭代示例如下:

// 使用 `..` 创建一个左闭右开的范围(0 到 9)
for i in 0..10 {println!("Value of i is: {}", i);
}// 使用 `..=` 创建一个闭区间的范围(0 到 10)
for i in 0..=10 {println!("Value of i is: {}", i);
}

注意:Range 类型产生的数值并不包括区间的上界,需要使用 ..= 语法才可以。当需要类似 C/C++ 风格的循环控制时,通常可以使用 Range 类型,这种方式也避免了因手动处理索引导致类似越界访问的错误。

Range 类型

在 Rust 中,Range 是一种迭代器类型,它生成一系列按顺序排列的数字。Range 通常用于 for 循环中,提供了一种简便的方式来执行重复操作一定次数的任务。

这里有两种最常用的 Range 类型:

  1. Range (start..end): 创建一个从 start 到 end(不包括)的迭代器,也就是左闭右开的区间。
  2. RangeInclusive (start..=end): 创建一个从 start 到 end(包括)的迭代器,闭区间,包含结束值。

创建 Range:

Range 通过使用两个点 .. 运算符来创建:

let a = 0..5; // 这将包括整数 0, 1, 2, 3, 4for i in a {println!("{}", i); // 打印 0 到 4。
}

创建 RangeInclusive:

RangeInclusive 通过使用三个点 ..= 运算符来创建:

let b = 0..=5; // 这将包括整数 0, 1, 2, 3, 4, 5for i in a {println!("{}", i); // 打印 0 到 5。
}

这两种类型都是迭代器,可以使用它们的 next 方法来逐个获取值,或者使用 for 循环来遍历这些值。

常用方法

Range 类型支持很多操作方法,下面列举几个常用的。

rev

rev 方法可以用来反转范围,创建一个新的迭代器,它会按照相反的顺序产生数值。

let range = (1..10).rev();
for num in range {println!("{num}"); // 将从 9 递减到 1
}
count

返回迭代器中剩余的元素数量。

let range_cnt = (1..100).count();
println!("{range_cnt}"); // 输出: 99
start_bound 和 end_bound

返回Range的起始边界和结束边界。返回的是一个Bound枚举,可以是Included(包含边界值)或Excluded(不包含边界值)。

let range = 1..100;
println!("{:?}", range.start_bound()); // 输出: Included(1)
println!("{:?}", range.end_bound());   // 输出: Excluded(100)
contains

判断一个指定的数值是否在Range内。如果是start..end类型的Range,会判断这个值是否大于等于start且小于end

let range = 1..100;
println!("{}", range.contains(&50));  // 输出: true
println!("{}", range.contains(&100)); // 输出: false
next

迭代Range并返回下一个值,如果迭代已经完成则返回None

let mut range = 1..3;
assert_eq!(range.next(), Some(1));
assert_eq!(range.next(), Some(2));
assert_eq!(range.next(), None);
last

返回Range中的最后一个数值,对 start..end 类型的Range来说,这个值是end - 1

let range = 1..100;
println!("{}", range.last().unwrap()); // 输出: 99
nth

获取迭代器中的第n个元素,并且将迭代器前进到此位置后面的元素。

let mut range = 1..100;
println!("{}", range.nth(49).unwrap()); // 输出: 50,即第50个元素
step_by

创建一个每n个数值产生一次的迭代器。

let range = (0..10).step_by(3);
for num in range {println!("{num}"); // 输出: 0, 3, 6, 9
}
其他

这个只列举了最常用的一些方法,Range 还支持很多其他的方法,此外,由于 Range 和 RangeInclusive 实现了 Iterator trait,因此提供了所有迭代器的标准方法,如 mapfilterfold, 和 collect 等。

结语

本章介绍了条件判断、循环语句以及 Range 类型,这是在程序开发中最常用的语句。在 Rust 中,不支持 do...whilefor ( i = 0; i <10; i++ )三元运算符 这类语法,但是可以用其他语法平替,这是从其他语言切换到 Rust 开发时需要注意的。

参考资料

  • Rust 圣经:https://doc.rust-lang.org/book/ch03-05-control-flow.html
  • Rust 实例:https://doc.rust-lang.org/rust-by-example/flow_control.html
  • Rust 标准库: https://doc.rust-lang.org/std/ops/struct.Range.html

相关文章:

  • ZYNQ:PL-CAN总线功能应用
  • CSS之重绘与回流
  • StringJoiner
  • GEE:关于在GEE平台上进行回归计算的若干问题
  • 3秒实现无痛基于Stable Diffusion WebUI安装ComfyUI!无需重复安装环境!无需重复下载模型!安装教程
  • 通过 Prometheus 编写 TiDB 巡检脚本(脚本已开源,内附链接)
  • 【Unity】【VR开发】针对VR项目的优化版Unity Build Settings
  • 人工智能学习与实训笔记(四):神经网络之NLP基础—词向量
  • [力扣 Hot100]Day28 两数相加
  • 使用 C++23 从零实现 RISC-V 模拟器(1):最简CPU
  • Java学习第十六节之类与对象的创建和构造器详解
  • 1.初识Tauri
  • ES实战-聚集
  • Rust基础拾遗--辅助功能
  • 惠普打印机驱动安装
  • 【Leetcode】101. 对称二叉树
  • Bootstrap JS插件Alert源码分析
  • iOS 颜色设置看我就够了
  • Node + FFmpeg 实现Canvas动画导出视频
  • SpiderData 2019年2月23日 DApp数据排行榜
  • web标准化(下)
  • 编写高质量JavaScript代码之并发
  • 订阅Forge Viewer所有的事件
  • 简析gRPC client 连接管理
  • 如何解决微信端直接跳WAP端
  • 使用agvtool更改app version/build
  • 手写一个CommonJS打包工具(一)
  • 项目管理碎碎念系列之一:干系人管理
  • 一个JAVA程序员成长之路分享
  • 怎么把视频里的音乐提取出来
  • 《码出高效》学习笔记与书中错误记录
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #AngularJS#$sce.trustAsResourceUrl
  • (2)STM32单片机上位机
  • (js)循环条件满足时终止循环
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (分布式缓存)Redis持久化
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (黑马C++)L06 重载与继承
  • (五)c52学习之旅-静态数码管
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • ******之网络***——物理***
  • **CI中自动类加载的用法总结
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET 8.0 发布到 IIS
  • .NET CLR Hosting 简介
  • .NET Core 中插件式开发实现
  • .net 流——流的类型体系简单介绍
  • .NET 指南:抽象化实现的基类
  • .NET多线程执行函数
  • .NET中winform传递参数至Url并获得返回值或文件
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945