首页 / Rust 入门教程 / if/else 控制流

Rust 入门教程

if/else 控制流

本教程共 78 篇 · 第 16 篇 · 更新于 2026-08-08 · 约 8 分钟阅读

RustRust 入门教程ifelse条件判断if 表达式控制流

本节目标:用 if/else 让程序做判断,理解 Rust 要求条件必须是 bool 类型,并掌握把 if 当表达式直接赋值给变量的写法,学会写出清晰的多分支判断。

程序不能只会自上而下一条直线跑,它得会根据情况走不同分支。比如”分数够 60 就及格,否则不及格”。这种”条件判断”靠 if/else 实现。Rust 的 if 和别的语言长得很像,但有个必须注意的硬性规定,理解了它,你以后写判断会顺手很多。

16-1 最基本的 if

先从一个最朴素的判断看起:

fn main() {
    let number = 7;
    if number < 5 {
        println!("小于 5");
    } else {
        println!("不小于 5");
    }
}

if 后面跟一对圆括号里的条件,再跟花括号里的代码块。条件成立就执行 if 块,否则走 else 块。这里有几个 Rust 的”小固执”你要先记住:圆括号可写可不写,但是花括号必须有。Rust 不允许像某些语言那样省略花括号只写单行,比如你没法写成 if x < 5 println!("小")。强制写花括号看似啰嗦,其实能挡掉很多”少加一对括号导致逻辑跑偏”的低级 bug——很多语言里那种 if 后面偷偷多挂一行代码的事故,在 Rust 里根本发生不了。

16-2 条件必须是 bool,没有”非零即真”

这是 Rust 和 C/C++ 系语言最大的区别之一,初学最容易栽在这里。

Warning

Rust 的 if 条件必须是 bool 类型。写 if number { }(number 是整数)会直接编译报错。你必须写成 if number != 0 { } 这种明确产出 true/false 的形式。这比 C 语言(非零即真)严格,但能挡掉大量逻辑纰漏。

为什么这么严?因为”非零即真”这种隐式转换,是无数 bug 的温床。比如你本想判断”指针不为空”,结果写成 if some_int,一旦 some_int 是 0 就进了 else 分支,程序行为和你以为的完全不同,而且编译器不会提醒你。Rust 干脆不让这种含糊的判断存在:条件必须清清楚楚是个布尔值。习惯之后你会发现,这反而让代码读起来更诚实——看见 if 你就知道它一定在判断一个真/假。

16-3 else if 处理多分支

不止两个分支时,用 else if 串起来:

fn main() {
    let score = 85;
    if score >= 90 {
        println!("优秀");
    } else if score >= 60 {
        println!("及格");
    } else {
        println!("不及格");
    }
}

程序从上往下判断,命中第一个为真的分支就执行并跳出。所以把”更严格/更具体”的条件放前面很重要——如果先把 >= 60 放前面,85 分会直接进”及格”而到不了”优秀”。这个顺序问题在写成绩、税率、折扣这种区间判断时特别常见,写的时候脑子里要过一遍”我的区间是左闭右开的吗、有没有重叠”。

Note

分支一多,else if 链会显得笨重。当判断基于同一个值的多种情况(比如匹配一个枚举)时,后面的 match 表达式更合适。这里先用 if 打基础,等学到 match 你会回来感谢它的简洁。

16-4 if 是表达式,可以赋值

前面讲过”一切皆表达式”。if 在 Rust 里也是表达式,它能产出一个值,直接赋给变量:

fn main() {
    let condition = true;
    let number = if condition { 5 } else { 6 };
    println!("number = {number}");
}

if condition { 5 } else { 6 } 整体是个表达式,condition 为真得 5、否则得 6,结果绑给 number。注意两个分支的末行都没打分号——因为它们要产值。这点和函数返回值一模一样:末尾不带分号表示”这个表达式的结果就是它”。这种写法好处是省掉一个临时变量和重复的赋值,把”二选一”压缩成一行,特别适合那种”根据条件挑一个值”的场景。

16-5 分支类型必须一致

因为 if 表达式整体要有一个类型,所以各个分支产值的类型必须相同:

let x = if true {
    5       // i32
} else {
    "six"   // &str —— 类型不一致,编译报错
};

一个分支返回整数、另一个返回字符串,编译器无法确定 x 的类型,直接报错。要返回不同”形状”的值,得用后面讲的枚举(enum)打包。这里记住一个直觉:if 表达式最终要给 x 一个确定的类型,两个分支给出的东西类型不一样,x 到底算啥?编译器拒绝兜底。所以写 if 赋值时,先想清楚”这个值统一是什么类型”。

Warning

新手常写出 if cond { 5; } else { 6 } 然后困惑”为什么 x 是 ()“。记住:分支末尾别加分号,否则分支就不产值了,整个 if 表达式退化成单元类型。和函数返回值规则一模一样。这个坑在刚接触”表达式”概念时几乎人人踩一次。

16-6 比较与逻辑运算符:把多个条件拼起来

条件里可以用 > < == != >= <= 比较,用 &&(且)||(或)!(非)组合:

let age = 20;
let has_ticket = true;
if age >= 18 && has_ticket {
    println!("可以入场");
}

&& 表示两边都为 true 才进;|| 表示有一边为 true 就进;! 是取反。&&|| 还有个贴心特性叫”短路求值”:比如 a && b,如果 a 已经是 false,编译器根本不会去算 b,因为结果已经定了。这在 b 是很耗时的判断、或者 b 依赖 a 为真才有意义时很有用(比如先判断指针非空、再去读它的字段)。

16-7 if 作为表达式的真实场景

光看玩具例子不够,看个日常里真会写的:根据分数给等级字母,用 if 表达式一行搞定。

fn grade(score: u32) -> &'static str {
    if score >= 90 {
        "A"
    } else if score >= 75 {
        "B"
    } else if score >= 60 {
        "C"
    } else {
        "D"
    }
}

这里 if 表达式整体产出一个 &str,直接作为函数的返回值。注意每个分支末尾都没分号。这种”用 if 选一个值返回”的写法,比先 let mut result = ""; 再在各自分支里赋值要干净。它把”判断”和”产出”揉进一个表达式,是 Rust 里非常地道的用法。

16-8 你可能会踩的坑

把几个高频错误集中说一下,省得你逐个撞:

  • 坑一:条件不是 boolif x { } 当 x 是数字时直接报错,老老实实写 if x != 0 { }
  • 坑二:分支末尾手滑打分号,导致 if 表达式不返回值,赋给变量后类型是 (),后面用它算数就报错。
  • 坑三:分支类型不一致,上面讲过了,两个分支必须产出同一类型。
  • 坑四:else if 顺序写反,宽泛条件压在前面,把具体条件”挡”住了,结果永远走不到正确的分支。
Tip

写完一串 if/else if,养成一个习惯:从上往下读每一条条件,问自己”前面那条会不会把后面该进的分支提前截走?“区间判断尤其要检查边界(比如 60 到底是及格还是不及格,两端各算一次)。这个检查能救你很多次。

16-9 小结

if/else 让程序学会”看情况走”。记住三件事:条件必须严格是 bool,没有非零即真;花括号不能省;if 是表达式,可以整体赋值给变量,但所有分支类型要一致、末尾别乱打分号。表达式式的写法在”按条件挑一个值”时特别顺手。下一章我们讲循环——让程序”重复干活”,先是 loop 无限循环。