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.
568tools/tools/rust-course/basic/flow-control.html

523 lines
70 KiB

<!DOCTYPE HTML>
<html lang="zh-CN" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>流程控制 - Rust语言圣经(Rust Course)</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<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.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../theme/style.css">
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var 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 type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item affix "><a href="../about-book.html">关于本书</a></li><li class="chapter-item affix "><a href="../into-rust.html">进入 Rust 编程世界</a></li><li class="chapter-item affix "><a href="../first-try/sth-you-should-not-do.html">避免从入门到放弃</a></li><li class="chapter-item affix "><a href="../community.html">社区和锈书</a></li><li class="chapter-item affix "><li class="part-title">Rust 语言基础学习</li><li class="spacer"></li><li class="chapter-item "><a href="../first-try/intro.html"><strong aria-hidden="true">1.</strong> 寻找牛刀,以便小试</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../first-try/installation.html"><strong aria-hidden="true">1.1.</strong> 安装 Rust 环境</a></li><li class="chapter-item "><a href="../first-try/editor.html"><strong aria-hidden="true">1.2.</strong> 墙推 VSCode!</a></li><li class="chapter-item "><a href="../first-try/cargo.html"><strong aria-hidden="true">1.3.</strong> 认识 Cargo</a></li><li class="chapter-item "><a href="../first-try/hello-world.html"><strong aria-hidden="true">1.4.</strong> 不仅仅是 Hello world</a></li><li class="chapter-item "><a href="../first-try/slowly-downloading.html"><strong aria-hidden="true">1.5.</strong> 下载依赖太慢了?</a></li></ol></li><li class="chapter-item expanded "><a href="../basic/intro.html"><strong aria-hidden="true">2.</strong> Rust 基础入门</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../basic/variable.html"><strong aria-hidden="true">2.1.</strong> 变量绑定与解构</a></li><li class="chapter-item "><a href="../basic/base-type/index.html"><strong aria-hidden="true">2.2.</strong> 基本类型</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../basic/base-type/numbers.html"><strong aria-hidden="true">2.2.1.</strong> 数值类型</a></li><li class="chapter-item "><a href="../basic/base-type/char-bool.html"><strong aria-hidden="true">2.2.2.</strong> 字符、布尔、单元类型</a></li><li class="chapter-item "><a href="../basic/base-type/statement-expression.html"><strong aria-hidden="true">2.2.3.</strong> 语句与表达式</a></li><li class="chapter-item "><a href="../basic/base-type/function.html"><strong aria-hidden="true">2.2.4.</strong> 函数</a></li></ol></li><li class="chapter-item "><a href="../basic/ownership/index.html"><strong aria-hidden="true">2.3.</strong> 所有权和借用</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../basic/ownership/ownership.html"><strong aria-hidden="true">2.3.1.</strong> 所有权</a></li><li class="chapter-item "><a href="../basic/ownership/borrowing.html"><strong aria-hidden="true">2.3.2.</strong> 引用与借用</a></li></ol></li><li class="chapter-item "><a href="../basic/compound-type/intro.html"><strong aria-hidden="true">2.4.</strong> 复合类型</a><a class="toggle"><div></div></a></li><li><ol class="section"><li class="chapter-item "><a href="../basic/compound-type/string-slice.html"><strong aria-hidden="true">2.4.1.</strong> 字符串与切片</a></li><li class="chapter-item "><a href="../basic/compound-type/tuple.html"><strong aria-hidden="true">2.4.2.</strong> 元组</a></li><li class="chapter-item "><a href="../basic/compound-type/struct.html"><strong aria-hidden="true">2.4.3.</strong> 结构体</a></li><li class="chapter-item "><a href="../basic/compound-type/enum.html"><strong aria-hidden="true">2.4.4.</strong> 枚举</a></li><li class="chapter-item "><a href="../basic/compound-type/array.html"><strong aria-hidden="true">2.4.5.</strong> 数组</a></li></ol></li><li class="chapter-item expanded "><a href="../basic/flow-control.html" class="active"><strong aria-hidden="true">2.5.</strong> 流程控制</a></li><li class="chapter-item "><a href="../basic/match-pattern/intro.html"><strong aria-hidden="true">2.6.</strong> 模式匹配</a><a class="to
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust语言圣经(Rust Course)</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/sunface/rust-course" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/sunface/rust-course/edit/main/src/basic/flow-control.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
// Get viewed page store
var viewed_key = 'mdbook-viewed';
var viewed_map = {};
try {
var viewed_storage = localStorage.getItem(viewed_key);
if (viewed_storage) {
viewed_map = JSON.parse(viewed_storage)
}
} catch (e) { }
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
// Apply viewed style
if (viewed_map[link.pathname]) {
link.classList.add('md-viewed')
}
});
// Mark viewed after 30s
setTimeout(function() {
viewed_map[location.pathname] = 1;
localStorage.setItem(viewed_key, JSON.stringify(viewed_map));
}, 30000)
</script>
<div id="content" class="content">
<!-- Page table of contents -->
<div class="sidetoc"><nav class="pagetoc"></nav></div>
<main>
<h1 id="流程控制"><a class="header" href="#流程控制">流程控制</a></h1>
<p>80 后应该都对学校的小混混记忆犹新,在那个时代,小混混们往往都认为自己是地下王者,管控着地下事务的流程,在我看来,他们就像代码中的流程控制一样,无处不在,很显眼,但是又让人懒得重视。</p>
<p>言归正传Rust 程序是从上而下顺序执行的,在此过程中,我们可以通过循环、分支等流程控制方式,更好的实现相应的功能。</p>
<h2 id="使用-if-来做分支控制"><a class="header" href="#使用-if-来做分支控制">使用 if 来做分支控制</a></h2>
<blockquote>
<p>if else 无处不在 -- 鲁迅</p>
</blockquote>
<p>但凡你能找到一门编程语言没有 <code>if else</code>,那么一定更要反馈给鲁迅,反正不是我说的:) 总之,只要你拥有其它语言的编程经验,就一定会有以下认知:<code>if else</code> <strong>表达式</strong>根据条件执行不同的代码分支:</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>if condition == true {
// A...
} else {
// B...
}
<span class="boring">}
</span></code></pre></pre>
<p>该代码读作:若 <code>condition</code> 的值为 <code>true</code>,则执行 <code>A</code> 代码,否则执行 <code>B</code> 代码。</p>
<p>先看下面代码:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};
println!(&quot;The value of number is: {}&quot;, number);
}
</code></pre></pre>
<p>以上代码有以下几点要注意:</p>
<ul>
<li><strong><code>if</code> 语句块是表达式</strong>,这里我们使用 <code>if</code> 表达式的返回值来给 <code>number</code> 进行赋值:<code>number</code> 的值是 <code>5</code></li>
<li><code>if</code> 来赋值时,要保证每个分支返回的类型一样(事实上,这种说法不完全准确,见<a href="https://course.rs/appendix/expressions.html#if%E8%A1%A8%E8%BE%BE%E5%BC%8F">这里</a>),此处返回的 <code>5</code><code>6</code> 就是同一个类型,如果返回类型不一致就会报错</li>
</ul>
<pre><code class="language-console">error[E0308]: if and else have incompatible types
--&gt; src/main.rs:4:18
|
4 | let number = if condition {
| __________________^
5 | | 5
6 | | } else {
7 | | &quot;six&quot;
8 | | };
| |_____^ expected integer, found &amp;str // 期望整数类型,但却发现&amp;str字符串切片
|
= note: expected type `{integer}`
found type `&amp;str`
</code></pre>
<h2 id="使用-else-if-来处理多重条件"><a class="header" href="#使用-else-if-来处理多重条件">使用 else if 来处理多重条件</a></h2>
<p>可以将 <code>else if</code><code>if</code><code>else</code> 组合在一起实现更复杂的条件分支判断:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let n = 6;
if n % 4 == 0 {
println!(&quot;number is divisible by 4&quot;);
} else if n % 3 == 0 {
println!(&quot;number is divisible by 3&quot;);
} else if n % 2 == 0 {
println!(&quot;number is divisible by 2&quot;);
} else {
println!(&quot;number is not divisible by 4, 3, or 2&quot;);
}
}
</code></pre></pre>
<p>程序执行时,会按照自上至下的顺序执行每一个分支判断,一旦成功,则跳出 <code>if</code> 语句块,最终本程序会匹配执行 <code>else if n % 3 == 0</code> 的分支,输出 <code>&quot;number is divisible by 3&quot;</code></p>
<p>有一点要注意,就算有多个分支能匹配,也只有第一个匹配的分支会被执行!</p>
<p>如果代码中有大量的 <code>else if </code> 会让代码变得极其丑陋,不过不用担心,下一章的 <code>match</code> 专门用以解决多分支模式匹配的问题。</p>
<h1 id="循环控制"><a class="header" href="#循环控制">循环控制</a></h1>
<p>循环无处不在,上到数钱,下到数年,你能想象的很多场景都存在循环,因此它也是流程控制中最重要的组成部分之一。</p>
<p>在 Rust 语言中有三种循环方式:<code>for</code><code>while</code><code>loop</code>,其中 <code>for</code> 循环是 Rust 循环王冠上的明珠。</p>
<h2 id="for-循环"><a class="header" href="#for-循环">for 循环</a></h2>
<p><code>for</code> 循环是 Rust 的大杀器:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
for i in 1..=5 {
println!(&quot;{}&quot;, i);
}
}
</code></pre></pre>
<p>以上代码循环输出一个从 1 到 5 的序列,简单粗暴,核心就在于 <code>for</code><code>in</code> 的联动,语义表达如下:</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>for 元素 in 集合 {
// 使用元素干一些你懂我不懂的事情
}
<span class="boring">}
</span></code></pre></pre>
<p>这个语法跟 JavaScript 还蛮像,应该挺好理解。</p>
<p>注意,使用 <code>for</code> 时我们往往使用集合的引用形式,除非你不想在后面的代码中继续使用该集合(比如我们这里使用了 <code>container</code> 的引用。如果不使用引用的话所有权会被转移move<code>for</code> 语句块中,后面就无法再使用这个集合了)</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>for item in &amp;container {
// ...
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>对于实现了 <code>copy</code> 特征的数组(例如 [i32; 10] )而言, <code>for item in arr</code> 并不会把 <code>arr</code> 的所有权转移,而是直接对其进行了拷贝,因此循环之后仍然可以使用 <code>arr</code></p>
</blockquote>
<p>如果想在循环中,<strong>修改该元素</strong>,可以使用 <code>mut</code> 关键字:</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>for item in &amp;mut collection {
// ...
}
<span class="boring">}
</span></code></pre></pre>
<p>总结如下:</p>
<table><thead><tr><th>使用方法</th><th>等价使用方式</th><th>所有权</th></tr></thead><tbody>
<tr><td><code>for item in collection</code></td><td><code>for item in IntoIterator::into_iter(collection)</code></td><td>转移所有权</td></tr>
<tr><td><code>for item in &amp;collection</code></td><td><code>for item in collection.iter()</code></td><td>不可变借用</td></tr>
<tr><td><code>for item in &amp;mut collection</code></td><td><code>for item in collection.iter_mut()</code></td><td>可变借用</td></tr>
</tbody></table>
<p>如果想在循环中<strong>获取元素的索引</strong></p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let a = [4, 3, 2, 1];
// `.iter()` 方法把 `a` 数组变成一个迭代器
for (i, v) in a.iter().enumerate() {
println!(&quot;第{}个元素是{}&quot;, i + 1, v);
}
}
</code></pre></pre>
<p>有同学可能会想到,如果我们想用 <code>for</code> 循环控制某个过程执行 10 次,但是又不想单独声明一个变量来控制这个流程,该怎么写?</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>for _ in 0..10 {
// ...
}
<span class="boring">}
</span></code></pre></pre>
<p>可以用 <code>_</code> 来替代 <code>i</code> 用于 <code>for</code> 循环中,在 Rust 中 <code>_</code> 的含义是忽略该值或者类型的意思,如果不使用 <code>_</code>,那么编译器会给你一个 <code>变量未使用的</code> 的警告。</p>
<p><strong>两种循环方式优劣对比</strong></p>
<p>以下代码,使用了两种循环方式:</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 第一种
let collection = [1, 2, 3, 4, 5];
for i in 0..collection.len() {
let item = collection[i];
// ...
}
// 第二种
for item in collection {
}
<span class="boring">}
</span></code></pre></pre>
<p>第一种方式是循环索引,然后通过索引下标去访问集合,第二种方式是直接循环集合中的元素,优劣如下:</p>
<ul>
<li><strong>性能</strong>:第一种使用方式中 <code>collection[index]</code> 的索引访问,会因为边界检查(Bounds Checking)导致运行时的性能损耗 —— Rust 会检查并确认 <code>index</code> 是否落在集合内,但是第二种直接迭代的方式就不会触发这种检查,因为编译器会在编译时就完成分析并证明这种访问是合法的</li>
<li><strong>安全</strong>:第一种方式里对 <code>collection</code> 的索引访问是非连续的,存在一定可能性在两次访问之间,<code>collection</code> 发生了变化,导致脏数据产生。而第二种直接迭代的方式是连续访问,因此不存在这种风险( 由于所有权限制,在访问过程中,数据并不会发生变化)。</li>
</ul>
<p>由于 <code>for</code> 循环无需任何条件限制,也不需要通过索引来访问,因此是最安全也是最常用的,通过与下面的 <code>while</code> 的对比,我们能看到为什么 <code>for</code> 会更加安全。</p>
<h2 id="continue"><a class="header" href="#continue"><code>continue</code></a></h2>
<p>使用 <code>continue</code> 可以跳过当前当次的循环,开始下次的循环:</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> for i in 1..4 {
if i == 2 {
continue;
}
println!(&quot;{}&quot;, i);
}
<span class="boring">}
</span></code></pre></pre>
<p>上面代码对 1 到 3 的序列进行迭代,且跳过值为 2 时的循环,输出如下:</p>
<pre><code class="language-console">1
3
</code></pre>
<h2 id="break"><a class="header" href="#break"><code>break</code></a></h2>
<p>使用 <code>break</code> 可以直接跳出当前整个循环:</p>
<pre><pre class="playground"><code class="language-rust edition2021">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> for i in 1..4 {
if i == 2 {
break;
}
println!(&quot;{}&quot;, i);
}
<span class="boring">}
</span></code></pre></pre>
<p>上面代码对 1 到 3 的序列进行迭代,在遇到值为 2 时的跳出整个循环,后面的循环不再执行,输出如下:</p>
<pre><code class="language-console">1
</code></pre>
<h2 id="while-循环"><a class="header" href="#while-循环">while 循环</a></h2>
<p>如果你需要一个条件来循环,当该条件为 <code>true</code> 时,继续循环,条件为 <code>false</code>,跳出循环,那么 <code>while</code> 就非常适用:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let mut n = 0;
while n &lt;= 5 {
println!(&quot;{}!&quot;, n);
n = n + 1;
}
println!(&quot;我出来了!&quot;);
}
</code></pre></pre>
<p><code>while</code> 循环,只有当 <code>n</code> 小于等于 <code>5</code> 时,才执行,否则就立刻跳出循环,因此在上述代码中,它会先从 <code>0</code> 开始,满足条件,进行循环,然后是 <code>1</code>,满足条件,进行循环,最终到 <code>6</code> 的时候,大于 5不满足条件跳出 <code>while</code> 循环,执行 <code>我出来了</code> 的打印,然后程序结束:</p>
<pre><code class="language-console">0!
1!
2!
3!
4!
5!
我出来了!
</code></pre>
<p>当然,你也可以用其它方式组合实现,例如 <code>loop</code>(无条件循环,将在下面介绍) + <code>if</code> + <code>break</code></p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let mut n = 0;
loop {
if n &gt; 5 {
break
}
println!(&quot;{}&quot;, n);
n+=1;
}
println!(&quot;我出来了!&quot;);
}
</code></pre></pre>
<p>可以看出,在这种循环场景下,<code>while</code> 要简洁的多。</p>
<p><strong>while vs for</strong></p>
<p>我们也能用 <code>while</code> 来实现 <code>for</code> 的功能:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index &lt; 5 {
println!(&quot;the value is: {}&quot;, a[index]);
index = index + 1;
}
}
</code></pre></pre>
<p>这里,代码对数组中的元素进行计数。它从索引 <code>0</code> 开始,并接着循环直到遇到数组的最后一个索引(这时,<code>index &lt; 5</code> 不再为真)。运行这段代码会打印出数组中的每一个元素:</p>
<pre><code class="language-console">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> 在某一时刻会到达值 5不过循环在其尝试从数组获取第六个值会越界之前就停止了。</p>
<p>但这个过程很容易出错;如果索引长度不正确会导致程序 <strong><em>panic</em></strong>。这也使程序更慢,因为编译器增加了运行时代码来对每次循环的每个元素进行条件检查。</p>
<p><code>for</code>循环代码如下:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!(&quot;the value is: {}&quot;, element);
}
}
</code></pre></pre>
<p>可以看出,<code>for</code> 并不会使用索引去访问数组,因此更安全也更简洁,同时避免 <code>运行时的边界检查</code>,性能更高。</p>
<h2 id="loop-循环"><a class="header" href="#loop-循环">loop 循环</a></h2>
<p>对于循环而言,<code>loop</code> 循环毋庸置疑,是适用面最高的,它可以适用于所有循环场景(虽然能用,但是在很多场景下, <code>for</code><code>while</code> 才是最优选择),因为 <code>loop</code> 就是一个简单的无限循环,你可以在内部实现逻辑通过 <code>break</code> 关键字来控制循环何时结束。</p>
<p>使用 <code>loop</code> 循环一定要打起精神,否则你会写出下面的跑满你一个 CPU 核心的疯子代码:</p>
<pre><code class="language-rust ignore">fn main() {
loop {
println!(&quot;again!&quot;);
}
}
</code></pre>
<p>该循环会不停的在终端打印输出,直到你使用 <code>Ctrl-C</code> 结束程序:</p>
<pre><code class="language-console">again!
again!
again!
again!
^Cagain!
</code></pre>
<p><strong>注意</strong>,不要轻易尝试上述代码,如果你电脑配置不行,可能会死机!!!</p>
<p>因此,当使用 <code>loop</code> 时,必不可少的伙伴是 <code>break</code> 关键字,它能让循环在满足某个条件时跳出:</p>
<pre><pre class="playground"><code class="language-rust edition2021">fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!(&quot;The result is {}&quot;, result);
}
</code></pre></pre>
<p>以上代码当 <code>counter</code> 递增到 <code>10</code> 时,就会通过 <code>break</code> 返回一个 <code>counter * 2</code> 的值,最后赋给 <code>result</code> 并打印出来。</p>
<p>这里有几点值得注意:</p>
<ul>
<li><strong>break 可以单独使用,也可以带一个返回值</strong>,有些类似 <code>return</code></li>
<li><strong>loop 是一个表达式</strong>,因此可以返回一个值</li>
</ul>
<h2 id="课后练习"><a class="header" href="#课后练习">课后练习</a></h2>
<blockquote>
<p><a href="https://zh.practice.rs/flow-control.html">Rust By Practice</a>,支持代码在线编辑和运行,并提供详细的<a href="https://github.com/sunface/rust-by-practice/blob/master/solutions/flow-control.md">习题解答</a></p>
</blockquote>
<div id="giscus-container"></div>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../basic/compound-type/array.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../basic/match-pattern/intro.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../basic/compound-type/array.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../basic/match-pattern/intro.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="../ace.js" type="text/javascript" charset="utf-8"></script>
<script src="../editor.js" type="text/javascript" charset="utf-8"></script>
<script src="../mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
var pagePath = "basic/flow-control.md"
</script>
<!-- Custom JS scripts -->
<script type="text/javascript" src="../assets/custom.js"></script>
<script type="text/javascript" src="../assets/bigPicture.js"></script>
</body>
</html>