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

【Rust】 3. 语句与表达式笔记

一、核心概念

  • 语句 (Statement):执行操作但不返回值的指令。其类型永远是单元类型 ()。

  • 表达式 (Expression):进行计算并产生一个值的代码片段。它总是有具体的类型。

  • 关系:表达式可以是语句的一部分(例如,在 let x = 6; 中,6 是表达式)。语句块(由 {} 包裹)本身也可以是表达式。

二、语句与表达式的区别

  1. 语句不返回值

fn main() {let a = (let b = 6); // 编译错误!
}
  • 错误原因:let b = 6; 是一个语句,它没有返回值。试图将一个语句(其值为 ())赋值给变量 a 会导致类型不匹配错误。
  1. 表达式返回值

fn main() {let b = {let a = 3; // 语句a + 1      // 表达式(注意:没有分号)};println!("The value of b is: {}", b); // 输出:The value of b is: 4
}
  • 关键点:块({})是一个表达式,它的值是块中最后一个表达式的值。

  • 分号的作用:在代码行末尾加上分号 ; 会将表达式转换为语句,从而使其不再返回值。上例中若在 a + 1 后加上分号,则该块的值会变为 (),导致 let b = ();,从而引发类型推断错误。

  1. 总结
  • 表达式产生一个值,有类型。

  • 语句不产生值,类型为 ()。

  • 表达式 + 分号 = 语句。

  • 语句块 ({…}) 可以包装语句和表达式,并使其整体作为一个表达式使用。

  • Rust 是表达式语言:if、while、for、loop、函数体等都可以返回 values。

三、算术与比较表达式

  1. 算术运算符

+ (加), - (减), * (乘), / (除), % (取余)


fn arithmetic_operation_test1() {let x = 100;let y = 10;println!("x+y={}, x-y={}, x*y={}, x/y={}, x%y={}", x+y, x-y, x*y, x/y, x%y);
}
  1. 比较运算符

== (等于), != (不等于), < (小于), > (大于), <= (小于等于), >= (大于等于)

  • 要求:比较双方类型必须相同且满足 PartialEq 约束。

  • 结果类型:bool。

  • 禁止连续比较:

fn compare_test(a: bool, b: bool, c: bool) -> bool {a == b == c // 编译错误!Rust 禁止这种连续比较语法。}
  • 错误分析:a == b 的结果是 bool 类型,再将这个 bool 值与 c (也是 bool) 进行比较在逻辑上是错误的((true == true) == true 在数学上成立,但 Rust 为避免歧义和常见错误,直接禁止此语法)。

四、赋值表达式

  • 形式:左值 = 右值

  • 类型:赋值表达式本身的类型是单元类型 (),值是空元组 ()。

  • 要求:左右两边类型必须相同。

  • 禁止连续赋值:

fn assignment_test() {let x: i32;let y: i32;let z = 10;x = y = z; // 编译错误!因为 `y = z` 的类型是 `()`,无法赋值给 `x: i32`。}

五、语句块表达式

  • 块 ({}) 的值由其最后一行决定。

  • 最后一行是表达式(无分号)=> 块的值即为该表达式的值。

  • 最后一行是语句(有分号)或没有最后一行 => 块的值是 ()。


fn block_expression_test() {let x: () = { println!("Hello World"); }; // 语句,类型为 ()let y: i32 = { println!("Hello World"); 5 }; // 5 是表达式,块的值是 5println!("x = {:?}", x); // 输出: x = ()println!("y = {}", y);   // 输出: y = 5
}

六、控制流表达式

  1. if-else 表达式
  • 条件:必须是 bool 类型。

  • 括号:不需要用小括号 () 包裹条件,用了反而会收到警告。

  • 分支:必须用大括号 {}。

  • 类型一致性:所有分支必须返回相同类型的值。


fn if_else_test() -> i32 {if 1 > 2 { // 条件无需括号1 // if 分支的值} else {2 // else 分支的值}// 整个 if-else 表达式的类型是 i32
}
  • 常见错误:遗漏 else 分支
fn if_missing_else() -> i32 {if true {1 // 类型是 i32}// 隐含的 else 分支返回 (),类型不匹配!}
  • 修复:确保所有可能路径都有返回且类型一致,或使用 return 提前返回。
  1. loop 循环
  • 无限循环。

  • break 可以跳出循环。

  • continue 跳过本次循环的剩余代码,进入下一次迭代。

  • 关键特性:loop 可以是一个表达式,break 后可以跟一个值作为整个 loop 表达式的返回值。

fn loop_expression() -> i32 {let mut counter = 0;let result = loop {counter += 1;if counter == 10 {break counter * 2; // break 返回值,整个 loop 的值就是 counter * 2}};result}
  1. loop vs while true
  • 语义差异:对编译器静态分析而言,loop {} 明确表示无限循环,而 while true {} 是一个条件循环。

  • 影响:编译器能更精确地分析 loop 块内的变量初始化情况。

let x;loop {x = 1;break;}println!("{}", x); // 编译成功!编译器知道 x 肯定被初始化了。let x;while true { // 编译器认为条件可能在运行时为 false(即使不会)x = 1;break;}println!("{}", x); // 编译错误!编译器认为 x 可能未初始化。
建议:需要无限循环时,优先使用 loop。
  1. while 循环
  • 条件循环。条件必须是 bool 类型。

  • 注意:while 循环本身不是表达式,其值永远是 ()。


fn while_test() {let mut n = 1;while n < 100 { // 条件无需括号// ... 循环体n += 1;}// while 循环的值是 ()
}
  1. for 循环
  • 用于迭代实现 Iterator trait 的集合(如数组、范围、Vec 等)。

  • 本质上是一种语法糖。

  • 不是表达式,其值为 ()。


fn for_test() {let array = [1, 2, 3, 4, 5];for element in array.iter() { // 使用迭代器println!("The number is {}", element);}// 等价写法:for element in &array { // 直接引用数组println!("The number is {}", element);}
}

七、常见错误总结

  1. 连续比较:

a == b == c // 错误!
// 应写成:a == b && b == c
  1. if 表达式遗漏 else 分支:

let n = if true { 10 }; // 错误!if 是 i32,隐含 else 是 ()
// 应补充 else 分支或使用其他控制流
  1. 误在表达式末尾加分号(尤其是在函数最后一行和块的最后一行):

fn foo() -> i32 {42; // 错误!变成了语句,返回 () 而非 i32
}
let x = { 42; }; // x 的类型是 (),而不是 i32
http://www.dtcms.com/a/354864.html

相关文章:

  • Flask测试平台开发实战-第一篇
  • 安科瑞三相智能安全配电装置在养老院配电系统中的应用
  • Flask测试平台开发,登陆重构
  • F010 Vue+Flask豆瓣图书推荐大数据可视化平台系统源码
  • 新型Zip Slip漏洞允许攻击者在解压过程中操纵ZIP文件
  • 大模型训练推理优化(5): FlexLink —— NVLink 带宽无损提升27%
  • Android Glide插件化开发实战:模块化加载与自定义扩展
  • 使用MySQL计算斐波那契数列
  • 三轴云台之闭环反馈技术篇
  • Vue + ECharts 中 Prop 数据被修改导致图表合并的问题及解决方案
  • Vibe Coding到底是什么:什么是 Vibe Coding?AI编程?
  • SpringCloud OpenFeign 远程调用(RPC)
  • Web网络开发 -- 常见CSS属性
  • 前端RSA加密遇到Java后端解密失败的问题解决
  • 创建uniApp小程序项目vue3+ts+uniapp
  • 文档格式转换软件 一键Word转PDF
  • PDF转长图工具,一键多页转图片
  • 【Deepseek】Windows MFC/Win32 常用核心 API 汇总
  • Spring Boot对访问密钥加解密——HMAC-SHA256
  • Docker Swarm 与 Kubernetes (K8s) 全面对比教程
  • SMU算法与人工智能创新实践班SMU2025 Summer 7th 参考题解
  • 虚幻基础:角色变换角色视角蒙太奇运动
  • Python篇---返回类型
  • 安卓/ios按键精灵脚本开发工具:OpenCV.FindImgAll命令介绍
  • 工业电子看板赋能线缆工厂生产高效运转
  • 可扩展系统设计的黄金法则与Go语言实践|得物技术
  • 血缘元数据采集开放标准:OpenLineage Integrations Apache Airflow Usage
  • 2026届大数据毕业设计选题推荐-基于大数据景点印象服务系统 爬虫数据可视化分析
  • 【Linux】linux中线程的引出
  • 视频软解码技术详解:原理、应用与未来发展