You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trpl-zh-cn/ch03-05-control-flow.html

536 lines
44 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>控制流 - Rust 程序设计语言 简体中文版</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon-de23e50b.svg">
<link rel="shortcut icon" href="favicon-8114d1fc.png">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="ferris-d33b75bf.css">
<link rel="stylesheet" href="theme/2018-edition-4e126c62.css">
<link rel="stylesheet" href="theme/semantic-notes-9b5766c0.css">
<link rel="stylesheet" href="theme/listing-cab26221.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-e0ffcbc3.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-fb31ca2f.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
sidebar_toggle.checked = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Rust 程序设计语言 简体中文版</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
<a href="https://github.com/KaiserY/trpl-zh-cn/tree/main" title="Git repository" aria-label="Git repository">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h2 id="控制流"><a class="header" href="#控制流">控制流</a></h2>
<p><a href="https://github.com/rust-lang/book/blob/9cc190796f28505c7a9a9cacea42f50d895ff3bd/src/ch03-05-control-flow.md">ch03-05-control-flow.md</a></p>
<p>根据条件是否为 <code>true</code> 来决定是否执行某些代码,以及在条件为 <code>true</code> 时重复执行某些代码的能力是大多数编程语言的基本构件。Rust 中最常见的控制执行流的结构是 <code>if</code> 表达式和循环。</p>
<h3 id="if-表达式"><a class="header" href="#if-表达式"><code>if</code> 表达式</a></h3>
<p><code>if</code> 表达式允许根据条件执行不同的代码分支。你提供一个条件并表示 “如果条件满足,运行这段代码;如果条件不满足,不运行这段代码。”</p>
<p><em>projects</em> 目录中创建一个名为 <em>branches</em> 的新项目,来体验 <code>if</code> 表达式。在 <em>src/main.rs</em> 文件中输入如下内容:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let number = 3;
if number &lt; 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}</code></pre>
<p>所有 <code>if</code> 表达式都以 <code>if</code> 关键字开头,后面紧跟一个条件。在这个例子中,条件会检查变量 <code>number</code> 的值是否小于 5。如果条件为 <code>true</code>,就执行紧跟在条件后面的大括号中的代码块。与 <code>if</code> 表达式中各个条件关联的代码块有时也被称为 <em>arms</em>,就像我们在第二章<a href="ch02-00-guessing-game-tutorial.html#比较猜测的数字和秘密数字">“比较猜测的数字和秘密数字”</a>一节中讨论过的 <code>match</code> 表达式分支一样。</p>
<p>也可以包含一个可选的 <code>else</code> 表达式来提供一个在条件为 <code>false</code> 时应当执行的代码块,这里我们就这么做了。如果不提供 <code>else</code> 表达式并且条件为 <code>false</code> 时,程序会直接忽略 <code>if</code> 代码块并继续执行下面的代码。</p>
<p>尝试运行代码,应该能看到如下输出:</p>
<pre><code class="language-console">$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/branches`
condition was true
</code></pre>
<p>尝试改变 <code>number</code> 的值使条件为 <code>false</code> 时看看会发生什么:</p>
<pre><code class="language-rust ignore"><span class="boring">fn main() {
</span> let number = 7;
<span class="boring">
</span><span class="boring"> if number &lt; 5 {
</span><span class="boring"> println!("condition was true");
</span><span class="boring"> } else {
</span><span class="boring"> println!("condition was false");
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
<p>再次运行程序并查看输出:</p>
<pre><code class="language-console">$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/branches`
condition was false
</code></pre>
<p>还值得注意的是,条件<strong>必须</strong><code>bool</code> 值。如果条件不是 <code>bool</code>,我们就会得到一个错误。例如,尝试运行下面这段代码:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">fn main() {
let number = 3;
if number {
println!("number was three");
}
}</code></pre>
<p>这里 <code>if</code> 条件的值是 <code>3</code>Rust 抛出了一个错误:</p>
<pre><code class="language-console">$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
error[E0308]: mismatched types
--&gt; src/main.rs:4:8
|
4 | if number {
| ^^^^^^ expected `bool`, found integer
For more information about this error, try `rustc --explain E0308`.
error: could not compile `branches` (bin "branches") due to 1 previous error
</code></pre>
<p>这个错误表明 Rust 期望得到的是一个 <code>bool</code>,却收到了一个整数。不同于 Ruby 或 JavaScript 这样的语言Rust 不会自动尝试把非布尔类型转换成布尔类型。你必须显式地为 <code>if</code> 提供一个布尔值作为条件。例如,如果我们希望 <code>if</code> 代码块只在某个数字不等于 <code>0</code> 时运行,就可以把 <code>if</code> 表达式改成下面这样:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let number = 3;
if number != 0 {
println!("number was something other than zero");
}
}</code></pre>
<p>运行代码会打印出 <code>number was something other than zero</code></p>
<h4 id="使用-else-if-处理多重条件"><a class="header" href="#使用-else-if-处理多重条件">使用 <code>else if</code> 处理多重条件</a></h4>
<p>可以将 <code>else if</code> 表达式与 <code>if</code><code>else</code> 组合来实现多重条件。例如:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}</code></pre>
<p>这个程序有四个可能的执行路径。运行后应该能看到如下输出:</p>
<pre><code class="language-console">$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/branches`
number is divisible by 3
</code></pre>
<p>当执行这个程序时,它按顺序检查每个 <code>if</code> 表达式并执行第一个条件为 <code>true</code> 的代码块。注意即使 6 可以被 2 整除,也不会输出 <code>number is divisible by 2</code>,更不会输出 <code>else</code> 块中的 <code>number is not divisible by 4, 3, or 2</code>。原因是 Rust 只会执行第一个条件为 <code>true</code> 的代码块,并且一旦它找到一个以后,甚至都不会检查剩下的条件了。</p>
<p>使用过多的 <code>else if</code> 表达式会让代码显得杂乱,所以如果你有不止一个 <code>else if</code>,可能就该考虑重构代码了。针对这种情况,第六章会介绍一个强大的 Rust 分支结构branching construct叫做 <code>match</code></p>
<h4 id="在-let-语句中使用-if"><a class="header" href="#在-let-语句中使用-if"><code>let</code> 语句中使用 <code>if</code></a></h4>
<p>因为 <code>if</code> 是一个表达式,我们可以在 <code>let</code> 语句的右侧使用它,例如在示例 3-2 中:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}</code></pre>
<p><span class="caption">示例 3-2<code>if</code> 表达式的返回值赋给一个变量</span></p>
<p>变量 <code>number</code> 会绑定到 <code>if</code> 表达式结果所产生的那个值。运行这段代码看看会发生什么:</p>
<pre><code class="language-console">$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
Running `target/debug/branches`
The value of number is: 5
</code></pre>
<p>记住,代码块的值就是其中最后一个表达式的值,而数字本身也是表达式。在这个例子中,整个 <code>if</code> 表达式的值取决于哪个代码块被执行。这意味着 <code>if</code> 的各个分支可能产生的结果值都必须是相同类型;在示例 3-2 中,<code>if</code> 分支和 <code>else</code> 分支的结果都是 <code>i32</code> 整数。如果类型不一致,就会像下面这个例子一样报错:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">fn main() {
let condition = true;
let number = if condition { 5 } else { "six" };
println!("The value of number is: {number}");
}</code></pre>
<p>当编译这段代码时,会得到一个错误。<code>if</code><code>else</code> 分支的值类型是不相容的,同时 Rust 也准确地指出在程序中的何处发现的这个问题:</p>
<pre><code class="language-console">$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
error[E0308]: `if` and `else` have incompatible types
--&gt; src/main.rs:4:44
|
4 | let number = if condition { 5 } else { "six" };
| - ^^^^^ expected integer, found `&amp;str`
| |
| expected because of this
For more information about this error, try `rustc --explain E0308`.
error: could not compile `branches` (bin "branches") due to 1 previous error
</code></pre>
<p><code>if</code> 代码块中的表达式会求值为一个整数,而 <code>else</code> 代码块中的表达式会求值为一个字符串。这是行不通的因为变量必须只有一个类型。Rust 需要在编译时就明确知道 <code>number</code> 的类型,这样它才能在编译阶段验证每一处对 <code>number</code> 的使用是否合法。如果 <code>number</code> 的类型只能在运行时确定Rust 就无法做到这一点;而如果编译器必须为每个变量跟踪多种假设类型,它也会变得更加复杂,并且对代码的保证会更少。</p>
<h3 id="使用循环重复执行"><a class="header" href="#使用循环重复执行">使用循环重复执行</a></h3>
<p>反复执行同一段代码是一件很常见的事,为此 Rust 提供了多种 <strong>循环</strong><em>loops</em>)。循环会执行循环体中的代码直到结尾,然后立即回到开头继续执行。为了体验循环,我们来新建一个叫做 <em>loops</em> 的项目。</p>
<p>Rust 有三种循环:<code>loop</code><code>while</code><code>for</code>。我们每一个都试试。</p>
<h4 id="使用-loop-重复执行代码"><a class="header" href="#使用-loop-重复执行代码">使用 <code>loop</code> 重复执行代码</a></h4>
<p><code>loop</code> 关键字告诉 Rust 反复执行一段代码,要么永远执行下去,要么直到你明确要求它停止。</p>
<p>作为一个例子,将 <em>loops</em> 目录中的 <em>src/main.rs</em> 文件修改为如下:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre><code class="language-rust ignore">fn main() {
loop {
println!("again!");
}
}</code></pre>
<p>运行这个程序时,我们会看到 <code>again!</code> 被不断重复打印,直到我们手动停止程序。大多数终端都支持使用快捷键 <kbd>ctrl</kbd>-<kbd>C</kbd> 来中断一个陷入无限循环的程序。试试看:</p>
<pre><code class="language-console">$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!
</code></pre>
<p>符号 <code>^C</code> 表示你在这里按下了 <kbd>ctrl</kbd>-<kbd>C</kbd>。在 <code>^C</code> 后面,你可能会看到,也可能不会看到 <code>again!</code>,这取决于代码在收到中断信号时正执行到循环的哪个位置。</p>
<p>幸运的是Rust 也提供了在代码中跳出循环的方法。你可以在循环中放置 <code>break</code> 关键字,告诉程序何时停止执行该循环。回忆一下,我们曾在第二章猜数字游戏的<a href="ch02-00-guessing-game-tutorial.html#猜测正确后退出">“猜测正确后退出”</a>一节中使用过它,让程序在用户猜中数字后退出。</p>
<p>我们在猜数字游戏中也使用过 <code>continue</code>。在循环里,<code>continue</code> 关键字会告诉程序跳过本次循环迭代剩余的代码,并直接进入下一次迭代。</p>
<h4 id="从循环返回值"><a class="header" href="#从循环返回值">从循环返回值</a></h4>
<p><code>loop</code> 的一个用途是重试那些你知道可能失败的操作,比如检查某个线程是否完成了任务。不过,你也可能希望把这个操作的结果传递给其他代码。为此,你可以在用于停止循环的 <code>break</code> 表达式后面加上想要返回的值;这个值会作为循环的返回值返回出来,因而你就可以使用它,如下所示:</p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}</code></pre>
<p>在循环之前,我们声明了一个名为 <code>counter</code> 的变量,并将其初始化为 <code>0</code>。然后,又声明了一个名为 <code>result</code> 的变量,用来保存循环返回的值。在循环的每次迭代中,我们都会给 <code>counter</code><code>1</code>,然后检查它是否等于 <code>10</code>。当条件满足时,就用 <code>break</code> 关键字返回 <code>counter * 2</code> 的值。循环结束后,我们用分号结束把值赋给 <code>result</code> 的那条语句。最后,打印出 <code>result</code> 的值,也就是 <code>20</code></p>
<p>如果你在循环内部使用 <code>return</code>,也可以从中返回。不过,<code>break</code> 只会退出当前循环,而 <code>return</code> 总是会退出当前函数。</p>
<h4 id="循环标签在多个循环之间消除歧义"><a class="header" href="#循环标签在多个循环之间消除歧义">循环标签:在多个循环之间消除歧义</a></h4>
<p>如果循环中又套了循环,那么 <code>break</code><code>continue</code> 默认只作用于当前最内层的那个循环。你可以选择给某个循环加上一个 <strong>循环标签</strong><em>loop label</em>),然后把这个标签和 <code>break</code><code>continue</code> 一起使用,这样这些关键字就会作用于被标记的循环,而不是最内层循环。下面是一个包含两层嵌套循环的例子:</p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}</code></pre>
<p>外层循环带有标签 <code>'counting_up</code>,它会从 0 数到 2。没有标签的内层循环则从 10 倒数到 9。第一个没有指定标签的 <code>break</code> 只会退出内层循环。语句 <code>break 'counting_up;</code> 则会退出外层循环。这段代码会打印:</p>
<pre><code class="language-console">$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58s
Running `target/debug/loops`
count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2
</code></pre>
<h4 id="while-条件循环"><a class="header" href="#while-条件循环"><code>while</code> 条件循环</a></h4>
<p>程序经常需要在循环中计算某个条件:只要条件为 <code>true</code>,循环就继续;当条件不再为 <code>true</code> 时,程序就会调用 <code>break</code> 来停止循环。这种循环类型可以通过组合 <code>loop</code><code>if</code><code>else</code><code>break</code> 来实现;如果你愿意,现在就可以在程序里试试看。不过,这种模式实在太常见了,所以 Rust 为它内置了一个语言结构,叫做 <code>while</code> 循环。在示例 3-3 中,我们使用 <code>while</code> 让程序循环三次,每次计数都减一;之后,在循环结束后打印另一条消息并退出。</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}</code></pre>
<p><span class="caption">示例 3-3: 当条件为 <code>true</code> 时,使用 <code>while</code> 循环运行代码</span></p>
<p>这种结构消除了使用 <code>loop</code><code>if</code><code>else</code><code>break</code> 时原本需要的大量嵌套,因此代码会更清晰。只要条件求值为 <code>true</code>,代码就会继续执行;否则就退出循环。</p>
<h4 id="使用-for-遍历集合"><a class="header" href="#使用-for-遍历集合">使用 <code>for</code> 遍历集合</a></h4>
<p>可以使用 <code>while</code> 结构来遍历集合中的元素,比如数组。例如,示例 3-4 中的循环会打印数组 <code>a</code> 中的每一个元素。</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index &lt; 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}</code></pre>
<p><span class="caption">示例 3-4使用 <code>while</code> 循环遍历集合中的每一个元素</span></p>
<p>这里,代码对数组中的元素进行计数。它从索引 <code>0</code> 开始,并接着循环直到遇到数组的最后一个索引(这时,<code>index &lt; 5</code> 不再为 <code>true</code>)。运行这段代码会打印出数组中的每一个元素:</p>
<pre><code class="language-console">$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.32s
Running `target/debug/loops`
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50
</code></pre>
<p>数组中的所有五个元素都如期出现在终端中。尽管 <code>index</code> 在某一时刻会到达值 <code>5</code>,不过循环在其尝试从数组获取第六个值(会越界)之前就停止了。</p>
<p>不过,这种方式很容易出错;如果索引值或测试条件写错了,就会导致程序 panic。例如如果你把数组 <code>a</code> 改成只有 4 个元素,却忘了把条件更新成 <code>while index &lt; 4</code>,代码就会 panic。它也会让程序变慢因为编译器会加入运行时代码在每次循环迭代时检查索引是否仍然位于数组边界之内。</p>
<p>作为更简洁的替代方案,可以使用 <code>for</code> 循环来对一个集合的每个元素执行一些代码。<code>for</code> 循环看起来如示例 3-5 所示:</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}</code></pre>
<p><span class="caption">示例 3-5使用 <code>for</code> 循环遍历集合中的元素</span></p>
<p>运行这段代码时,你会看到和示例 3-4 相同的输出。更重要的是,我们提高了代码的安全性,并消除了那种可能因为越过数组末尾,或遍历不够完整而漏掉某些元素所导致的 bug。</p>
<p>例如,在示例 3-4 的代码中,如果你把数组 <code>a</code> 改成只有 4 个元素,却忘了把条件更新为 <code>while index &lt; 4</code>,代码就会 panic。而使用 <code>for</code> 循环时,你就不必记着在修改数组元素个数时还要同步修改其他代码了。</p>
<p><code>for</code> 循环的安全性和简洁性,使它成为 Rust 中最常用的循环结构。即使是在你只想把某段代码执行特定次数的情况下,比如示例 3-3 里那个使用 <code>while</code> 的倒计时例子,大多数 Rustaceans 也会选择使用 <code>for</code> 循环。实现这种写法的方式是使用 <code>Range</code>,这是标准库提供的一种类型,用来生成从某个数字开始、到另一个数字之前结束的所有数字序列。</p>
<p>下面是一个使用 <code>for</code> 循环来倒计时的例子,它还用到了一个我们尚未讲到的方法 <code>rev</code>,用于反转 range。</p>
<p><span class="filename">文件名src/main.rs</span></p>
<pre class="playground"><code class="language-rust edition2024">fn main() {
for number in (1..4).rev() {
println!("{number}!");
}
println!("LIFTOFF!!!");
}</code></pre>
<p>这段代码是不是更好一些?</p>
<h2 id="总结"><a class="header" href="#总结">总结</a></h2>
<p>你做到了!这是内容相当丰富的一章:你学习了变量、标量和复合数据类型、函数、注释、<code>if</code> 表达式以及循环!如果你想练习本章讨论的概念,可以尝试构建下面这些程序:</p>
<ul>
<li>相互转换摄氏与华氏温度。</li>
<li>生成第 n 个斐波那契数。</li>
<li>打印圣诞颂歌 “The Twelve Days of Christmas” 的歌词,并利用歌曲中的重复部分(通过编写循环)。</li>
</ul>
<p>当你准备好继续时,我们将讨论一个在其他编程语言中<strong>并不</strong>常见的概念所有权ownership</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch03-04-comments.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="ch04-00-understanding-ownership.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ch03-04-comments.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="ch04-00-understanding-ownership.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr-ef4e11c1.min.js"></script>
<script src="mark-09e88c2c.min.js"></script>
<script src="searcher-c2a407aa.js"></script>
<script src="clipboard-1626706a.min.js"></script>
<script src="highlight-abc7f01d.js"></script>
<script src="book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
<script src="ferris-2317480c.js"></script>
</div>
</body>
</html>