|
|
<!DOCTYPE HTML>
|
|
|
<html lang="en" class="light sidebar-visible" dir="ltr">
|
|
|
<head>
|
|
|
<!-- Book generated using mdBook -->
|
|
|
<meta charset="UTF-8">
|
|
|
<title>使用字符串储存 UTF-8 编码的文本 - 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-7d935aa5.js";
|
|
|
</script>
|
|
|
<!-- Start loading toc.js asap -->
|
|
|
<script src="toc-9d5d6d0e.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="使用字符串储存-utf-8-编码的文本"><a class="header" href="#使用字符串储存-utf-8-编码的文本">使用字符串储存 UTF-8 编码的文本</a></h2>
|
|
|
<!-- https://github.com/rust-lang/book/blob/main/src/ch08-02-strings.md -->
|
|
|
<!-- commit 3a30e4c1fbe641afc066b3af9eb01dcdf5ed8b24 -->
|
|
|
<p>第四章已经讲过一些字符串的内容,不过现在让我们更深入地了解它。字符串是新晋 Rustacean 们通常会被困住的领域,这是由于三方面理由的结合:Rust 倾向于确保暴露出可能的错误,字符串是比很多程序员所想象的要更为复杂的数据结构,以及 UTF-8。所有这些要素结合起来对于来自其他语言背景的程序员就可能显得很困难了。</p>
|
|
|
<p>在集合章节中讨论字符串的原因是,字符串就是作为字节的集合外加一些方法实现的,当这些字节被解释为文本时,这些方法提供了实用的功能。在本小节中,我们会讲到 <code>String</code> 中那些任何集合类型都有的操作,比如创建、更新和读取。也会讨论 <code>String</code> 与其他集合不一样的地方,例如索引 <code>String</code> 是很复杂的,由于人和计算机理解 <code>String</code> 数据方式的不同。</p>
|
|
|
<h3 id="什么是字符串"><a class="header" href="#什么是字符串">什么是字符串?</a></h3>
|
|
|
<p>我们先定义一下<strong>字符串</strong>这一术语的具体意义。Rust 的核心语言中只有一种字符串类型,字符串 slice <code>str</code>,它通常以被借用的形式出现,<code>&str</code>。第四章讲到了<strong>字符串 slices</strong>:它们是一些对储存在别处的 UTF-8 编码字符串数据的引用。举例来说,由于字符串字面值被储存在程序的二进制输出中,因此它们也是字符串 slices。</p>
|
|
|
<p>字符串(<code>String</code>)类型由 Rust 标准库提供,而不是编入核心语言,它是一种可增长、可变、可拥有、UTF-8 编码的字符串类型。当 Rustaceans 提及 Rust 中的 “字符串 “时,他们可能指的是 <code>String</code> 或 string slice <code>&str</code> 类型,而不仅仅是其中一种类型。虽然本节主要讨论 <code>String</code>,但这两种类型在 Rust 的标准库中都有大量使用,而且 <code>String</code> 和 字符串 slices 都是 UTF-8 编码的。</p>
|
|
|
<h3 id="新建字符串"><a class="header" href="#新建字符串">新建字符串</a></h3>
|
|
|
<p>很多 <code>Vec<T></code> 上可用的操作在 <code>String</code> 中同样可用,事实上 <code>String</code> 被实现为一个带有一些额外保证、限制和功能的字节 vector 的封装。其中一个同样作用于 <code>Vec<T></code> 和 <code>String</code> 函数的例子是用来新建一个实例的 <code>new</code> 函数,如示例 8-11 所示。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let mut s = String::new();
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-11:新建一个空的 <code>String</code></span></p>
|
|
|
<p>这新建了一个叫做 <code>s</code> 的空的字符串,接着我们可以向其中加载数据。通常字符串会有初始数据,因为我们希望一开始就有这个字符串。为此,可以使用 <code>to_string</code> 方法,它能用于任何实现了 <code>Display</code> trait 的类型,比如字符串字面值。示例 8-12 展示了两个例子。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let data = "initial contents";
|
|
|
|
|
|
let s = data.to_string();
|
|
|
|
|
|
// 该方法也可直接用于字符串字面值:
|
|
|
let s = "initial contents".to_string();
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-12:使用 <code>to_string</code> 方法从字符串字面值创建 <code>String</code></span></p>
|
|
|
<p>这些代码会创建包含 <code>initial contents</code> 的字符串。</p>
|
|
|
<p>也可以使用 <code>String::from</code> 函数来从字符串字面值创建 <code>String</code>。示例 8-13 中的代码等同于使用 <code>to_string</code>。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let s = String::from("initial contents");
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-13:使用 <code>String::from</code> 函数从字符串字面值创建 <code>String</code></span></p>
|
|
|
<p>因为字符串应用广泛,这里有很多不同的用于字符串的通用 API 可供选择。其中一些可能看起来多余,不过都有其用武之地!在这个例子中,<code>String::from</code> 和 <code>.to_string</code> 最终做了完全相同的工作,所以如何选择就是代码风格与可读性的问题了。</p>
|
|
|
<p>记住字符串是 UTF-8 编码的,所以可以包含任何经过正确编码的数据,如示例 8-14 所示。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let hello = String::from("السلام عليكم");
|
|
|
let hello = String::from("Dobrý den");
|
|
|
let hello = String::from("Hello");
|
|
|
let hello = String::from("שלום");
|
|
|
let hello = String::from("नमस्ते");
|
|
|
let hello = String::from("こんにちは");
|
|
|
let hello = String::from("안녕하세요");
|
|
|
let hello = String::from("你好");
|
|
|
let hello = String::from("Olá");
|
|
|
let hello = String::from("Здравствуйте");
|
|
|
let hello = String::from("Hola");
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-14:在字符串中储存不同语言的问候语</span></p>
|
|
|
<p>所有这些都是有效的 <code>String</code> 值。</p>
|
|
|
<h3 id="更新字符串"><a class="header" href="#更新字符串">更新字符串</a></h3>
|
|
|
<p><code>String</code> 的大小可以增加,其内容也可以改变,就像可以放入更多数据来改变 <code>Vec</code> 的内容一样。另外,可以方便的使用 <code>+</code> 运算符或 <code>format!</code> 宏来拼接 <code>String</code> 值。</p>
|
|
|
<h4 id="使用-push_str-和-push-附加字符串"><a class="header" href="#使用-push_str-和-push-附加字符串">使用 <code>push_str</code> 和 <code>push</code> 附加字符串</a></h4>
|
|
|
<p>可以通过 <code>push_str</code> 方法来附加字符串 slice,从而使 <code>String</code> 变长,如示例 8-15 所示。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let mut s = String::from("foo");
|
|
|
s.push_str("bar");
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-15:使用 <code>push_str</code> 方法向 <code>String</code> 附加字符串 slice</span></p>
|
|
|
<p>执行这两行代码之后,<code>s</code> 将会包含 <code>foobar</code>。<code>push_str</code> 方法采用字符串 slice,因为我们并不需要获取参数的所有权。例如,示例 8-16 中我们希望在将 <code>s2</code> 的内容附加到 <code>s1</code> 之后还能使用它。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let mut s1 = String::from("foo");
|
|
|
let s2 = "bar";
|
|
|
s1.push_str(s2);
|
|
|
println!("s2 is {s2}");
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-16:将字符串 slice 的内容附加到 <code>String</code> 后使用它</span></p>
|
|
|
<p>如果 <code>push_str</code> 方法获取了 <code>s2</code> 的所有权,就不能在最后一行打印出其值了。好在代码如我们期望那样工作!</p>
|
|
|
<p><code>push</code> 方法被定义为获取一个单独的字符作为参数,并附加到 <code>String</code> 中。示例 8-17 展示了使用 <code>push</code> 方法将字母 <code>l</code> 加入 <code>String</code> 的代码。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let mut s = String::from("lo");
|
|
|
s.push('l');
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-17:使用 <code>push</code> 将一个字符加入 <code>String</code> 值中</span></p>
|
|
|
<p>执行这些代码之后,<code>s</code> 将会包含 <code>lol</code>。</p>
|
|
|
<h4 id="使用--运算符或-format-宏拼接字符串"><a class="header" href="#使用--运算符或-format-宏拼接字符串">使用 <code>+</code> 运算符或 <code>format!</code> 宏拼接字符串</a></h4>
|
|
|
<p>通常你会希望将两个已知的字符串合并在一起。一种办法是像这样使用 <code>+</code> 运算符,如示例 8-18 所示。</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let s1 = String::from("Hello, ");
|
|
|
let s2 = String::from("world!");
|
|
|
let s3 = s1 + &s2; // 注意 s1 被移动了,不能继续使用
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-18:使用 <code>+</code> 运算符将两个 <code>String</code> 值合并到一个新的 <code>String</code> 值中</span></p>
|
|
|
<p>执行完这些代码之后,字符串 <code>s3</code> 将会包含 <code>Hello, world!</code>。<code>s1</code> 在相加后不再有效的原因,和使用 <code>s2</code> 的引用的原因,与使用 <code>+</code> 运算符时调用的函数签名有关。<code>+</code> 运算符使用了 <code>add</code> 函数,这个函数签名看起来像这样:</p>
|
|
|
<pre><code class="language-rust ignore">fn add(self, s: &str) -> String {</code></pre>
|
|
|
<p>在标准库中你会发现,<code>add</code> 的定义使用了泛型和关联类型。在这里我们替换为了具体类型,这也正是当使用 <code>String</code> 值调用这个方法会发生的。第十章会讨论泛型。这个签名提供了理解 <code>+</code> 运算那微妙部分的线索。</p>
|
|
|
<p>首先,<code>s2</code> 使用了 <code>&</code>,意味着我们使用第二个字符串的<strong>引用</strong>与第一个字符串相加。这是因为 <code>add</code> 函数的 <code>s</code> 参数:只能将 <code>&str</code> 和 <code>String</code> 相加,不能将两个 <code>String</code> 值相加。不过等一下 —— <code>&s2</code> 的类型是 <code>&String</code>, 而不是 <code>add</code> 第二个参数所指定的 <code>&str</code>。那么为什么示例 8-18 还能编译呢?</p>
|
|
|
<p>之所以能够在 <code>add</code> 调用中使用 <code>&s2</code> 是因为 <code>&String</code> 可以被 <strong>强转</strong>(<em>coerced</em>)成 <code>&str</code>。当<code>add</code>函数被调用时,Rust 使用了一个被称为 <strong>Deref 强制转换</strong>(<em>deref coercion</em>)的技术,实际上会把 <code>&s2</code> 转换为 <code>&s2[..]</code>。第十五章会更深入的讨论 Deref 强制转换。因为 <code>add</code> 没有获取参数的所有权,所以在这个操作后 <code>s2</code> 仍然是有效的 <code>String</code>。</p>
|
|
|
<p>其次,可以发现签名中 <code>add</code> 获取了 <code>self</code> 的所有权,因为 <code>self</code> <strong>没有</strong>使用 <code>&</code>。这意味着示例 8-18 中的 <code>s1</code> 的所有权将被移动到 <code>add</code> 调用中,之后就不再有效。所以虽然 <code>let s3 = s1 + &s2;</code> 看起来就像它会复制两个字符串并创建一个新的字符串,而实际上这个语句会获取 <code>s1</code> 的所有权,附加上从 <code>s2</code> 中拷贝的内容,并返回结果的所有权。换句话说,它看起来好像生成了很多拷贝,不过实际上并没有:这个实现比拷贝要更高效。</p>
|
|
|
<p>如果想要级联多个字符串,<code>+</code> 运算符的行为就显得笨重了:</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let s1 = String::from("tic");
|
|
|
let s2 = String::from("tac");
|
|
|
let s3 = String::from("toe");
|
|
|
|
|
|
let s = s1 + "-" + &s2 + "-" + &s3;
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p>这时 <code>s</code> 的内容会是 <code>tic-tac-toe</code>。在有这么多 <code>+</code> 和 <code>"</code> 字符的情况下,很难理解具体发生了什么。对于更为复杂的字符串链接,可以使用 <code>format!</code> 宏:</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span> let s1 = String::from("tic");
|
|
|
let s2 = String::from("tac");
|
|
|
let s3 = String::from("toe");
|
|
|
|
|
|
let s = format!("{s1}-{s2}-{s3}");
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p>这些代码也会将 <code>s</code> 设置为 <code>tic-tac-toe</code>。<code>format!</code> 与 <code>println!</code> 的工作原理相同,不过不同于将输出打印到屏幕上,它返回一个带有结果内容的 <code>String</code>。这个版本就好理解的多,宏 <code>format!</code> 生成的代码使用引用因此不会获取任何参数的所有权。</p>
|
|
|
<h3 id="索引字符串"><a class="header" href="#索引字符串">索引字符串</a></h3>
|
|
|
<p>在很多语言中,通过索引来引用字符串中的单独字符是有效且常见的操作。然而在 Rust 中,如果你尝试使用索引语法访问 <code>String</code> 的一部分,会出现一个错误。考虑一下如示例 8-19 中所示的无效代码。</p>
|
|
|
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
|
|
|
</span> let s1 = String::from("hi");
|
|
|
let h = s1[0];
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p><span class="caption">示例 8-19:尝试对字符串使用索引语法</span></p>
|
|
|
<p>这段代码会导致如下错误:</p>
|
|
|
<pre><code class="language-console">$ cargo run
|
|
|
Compiling collections v0.1.0 (file:///projects/collections)
|
|
|
error[E0277]: the type `str` cannot be indexed by `{integer}`
|
|
|
--> src/main.rs:3:16
|
|
|
|
|
|
|
3 | let h = s1[0];
|
|
|
| ^ string indices are ranges of `usize`
|
|
|
|
|
|
|
= note: you can use `.chars().nth()` or `.bytes().nth()`
|
|
|
for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
|
|
|
= help: the trait `SliceIndex<str>` is not implemented for `{integer}`
|
|
|
but trait `SliceIndex<[_]>` is implemented for `usize`
|
|
|
= help: for that trait implementation, expected `[_]`, found `str`
|
|
|
= note: required for `String` to implement `Index<{integer}>`
|
|
|
|
|
|
For more information about this error, try `rustc --explain E0277`.
|
|
|
error: could not compile `collections` (bin "collections") due to 1 previous error
|
|
|
</code></pre>
|
|
|
<p>错误和提示说明了全部问题:Rust 的字符串不支持索引。那么,为什么会这样呢?为了回答这个问题,我们必须先聊一聊 Rust 是如何在内存中储存字符串的。</p>
|
|
|
<h4 id="内部表现"><a class="header" href="#内部表现">内部表现</a></h4>
|
|
|
<p><code>String</code> 是一个 <code>Vec<u8></code> 的封装。让我们看看示例 8-14 中一些正确编码的字符串的例子。首先是这一例:</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span><span class="boring"> let hello = String::from("السلام عليكم");
|
|
|
</span><span class="boring"> let hello = String::from("Dobrý den");
|
|
|
</span><span class="boring"> let hello = String::from("Hello");
|
|
|
</span><span class="boring"> let hello = String::from("שלום");
|
|
|
</span><span class="boring"> let hello = String::from("नमस्ते");
|
|
|
</span><span class="boring"> let hello = String::from("こんにちは");
|
|
|
</span><span class="boring"> let hello = String::from("안녕하세요");
|
|
|
</span><span class="boring"> let hello = String::from("你好");
|
|
|
</span><span class="boring"> let hello = String::from("Olá");
|
|
|
</span><span class="boring"> let hello = String::from("Здравствуйте");
|
|
|
</span> let hello = String::from("Hola");
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p>在这里,<code>len</code> 的值是 <code>4</code>,这意味着储存字符串 <code>"Hola"</code> 的 vector 的长度是四个字节:这里每一个字母的 UTF-8 编码都占用一个字节。下面这一行可能会让你感到意外(注意这个字符串中的首字母是西里尔字母的 <em>Ze</em> 而不是数字 3。):</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">fn main() {
|
|
|
</span><span class="boring"> let hello = String::from("السلام عليكم");
|
|
|
</span><span class="boring"> let hello = String::from("Dobrý den");
|
|
|
</span><span class="boring"> let hello = String::from("Hello");
|
|
|
</span><span class="boring"> let hello = String::from("שלום");
|
|
|
</span><span class="boring"> let hello = String::from("नमस्ते");
|
|
|
</span><span class="boring"> let hello = String::from("こんにちは");
|
|
|
</span><span class="boring"> let hello = String::from("안녕하세요");
|
|
|
</span><span class="boring"> let hello = String::from("你好");
|
|
|
</span><span class="boring"> let hello = String::from("Olá");
|
|
|
</span> let hello = String::from("Здравствуйте");
|
|
|
<span class="boring"> let hello = String::from("Hola");
|
|
|
</span><span class="boring">}</span></code></pre>
|
|
|
<p>如果有人问及该字符串的长度,你可能会回答 12。然而,Rust 的回答是 24:这是使用 UTF-8 编码 “Здравствуйте” 所需要的字节数,这是因为在这个字符串中每个 Unicode 标量值需要两个字节存储。因此一个字符串字节值的索引并不总是对应一个有效的 Unicode 标量值。作为演示,考虑如下无效的 Rust 代码:</p>
|
|
|
<pre><code class="language-rust ignore does_not_compile">let hello = "Здравствуйте";
|
|
|
let answer = &hello[0];</code></pre>
|
|
|
<p>我们已经知道 <code>answer</code> 不是第一个字符 <code>З</code>。当使用 UTF-8 编码时,<code>З</code> 的第一个字节是 <code>208</code>,第二个是 <code>151</code>,所以 <code>answer</code> 实际上应该是 <code>208</code>,不过 <code>208</code> 自身并不是一个有效的字母。返回 <code>208</code> 可不是一个请求字符串第一个字母的人所希望看到的,不过它是 Rust 在字节索引 0 位置所能提供的唯一数据。用户通常不会想要一个字节值被返回,即使这个字符串只有拉丁字母,如果 <code>&"hi"[0]</code> 是返回字节值的有效代码,它也会返回 <code>104</code> 而不是 <code>h</code>。</p>
|
|
|
<p>为了避免返回意外的值并造成不能立刻发现的 bug,Rust 根本不会编译这些代码,并在开发过程中及早杜绝了误会的发生。</p>
|
|
|
<h4 id="字节标量值和字形簇天呐"><a class="header" href="#字节标量值和字形簇天呐">字节、标量值和字形簇!天呐!</a></h4>
|
|
|
<p>这引起了关于 UTF-8 的另外一个问题:从 Rust 的角度来讲,事实上有三种相关方式可以查看字符串:字节、标量值和字形簇(最接近人们眼中 <strong>字母</strong>(<em>letters</em>)的概念)。</p>
|
|
|
<p>比如这个用梵文书写的印度语单词 “नमस्ते”,最终它储存在 vector 中的 <code>u8</code> 值看起来像这样:</p>
|
|
|
<pre><code class="language-text">[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
|
|
|
224, 165, 135]
|
|
|
</code></pre>
|
|
|
<p>这里有 18 个字节,也就是计算机最终会储存的数据。如果从 Unicode 标量值的角度理解它们,也就像 Rust 的 <code>char</code> 类型那样,这些字节看起来像这样:</p>
|
|
|
<pre><code class="language-text">['न', 'म', 'स', '्', 'त', 'े']
|
|
|
</code></pre>
|
|
|
<p>这里有六个 <code>char</code>,不过第四个和第六个都不是字母,它们是发音符号本身并没有任何意义。最后,如果以字形簇的角度理解,就会得到人们所说的构成这个单词的四个字母:</p>
|
|
|
<pre><code class="language-text">["न", "म", "स्", "ते"]
|
|
|
</code></pre>
|
|
|
<p>Rust 提供了多种不同的方式来解释计算机储存的原始字符串数据,这样程序就可以选择它需要的表现方式,而无所谓是何种人类语言。</p>
|
|
|
<p>最后一个 Rust 不允许使用索引获取 <code>String</code> 字符的原因是,索引操作预期总是需要常数时间(O(1))。但是对于 <code>String</code> 不可能保证这样的性能,因为 Rust 必须从开头到索引位置遍历来确定有多少有效的字符。</p>
|
|
|
<h3 id="字符串-slice"><a class="header" href="#字符串-slice">字符串 slice</a></h3>
|
|
|
<p>索引字符串通常是一个坏点子,因为字符串索引应该返回的类型是不明确的:字节值、字符、字形簇或者字符串 slice。因此,如果你真的希望使用索引创建字符串 slice 时,Rust 会要求你更明确一些。为了更明确索引并表明你需要一个字符串 slice,相比使用 <code>[]</code> 和单个值的索引,可以使用 <code>[]</code> 和一个 range 来创建含特定字节的字符串 slice:</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>let hello = "Здравствуйте";
|
|
|
|
|
|
let s = &hello[0..4];
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p>这里,<code>s</code> 会是一个 <code>&str</code>,它包含字符串的头四个字节。早些时候,我们提到了这些字母都是两个字节长的,所以这意味着 <code>s</code> 将会是 <code>Зд</code>。</p>
|
|
|
<p>如果尝试用类似 <code>&hello[0..1]</code> 的方式对字符的部分字节进行 slice,Rust 会在运行时 panic,就跟访问 vector 中的无效索引时一样:</p>
|
|
|
<pre><code class="language-console">$ cargo run
|
|
|
Compiling collections v0.1.0 (file:///projects/collections)
|
|
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.43s
|
|
|
Running `target/debug/collections`
|
|
|
|
|
|
thread 'main' panicked at src/main.rs:4:19:
|
|
|
byte index 1 is not a char boundary; it is inside 'З' (bytes 0..2) of `Здравствуйте`
|
|
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
|
</code></pre>
|
|
|
<p>在使用 range 来创建字符串 slice 时要格外小心,因为这么做可能会使你的程序崩溃。</p>
|
|
|
<h3 id="遍历字符串的方法"><a class="header" href="#遍历字符串的方法">遍历字符串的方法</a></h3>
|
|
|
<p>操作字符串每一部分的最好的方法是明确表示需要字符还是字节。对于单独的 Unicode 标量值使用 <code>chars</code> 方法。对 “Зд” 调用 <code>chars</code> 方法会将其分开并返回两个 <code>char</code> 类型的值,接着就可以遍历其结果来访问每一个元素了:</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>for c in "Зд".chars() {
|
|
|
println!("{c}");
|
|
|
}
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p>这些代码会打印出如下内容:</p>
|
|
|
<pre><code class="language-text">З
|
|
|
д
|
|
|
</code></pre>
|
|
|
<p>另外 <code>bytes</code> 方法返回每一个原始字节,这可能会适合你的使用场景:</p>
|
|
|
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>for b in "Зд".bytes() {
|
|
|
println!("{b}");
|
|
|
}
|
|
|
<span class="boring">}</span></code></pre>
|
|
|
<p>这些代码会打印出组成字符串的四个字节:</p>
|
|
|
<pre><code class="language-text">208
|
|
|
151
|
|
|
208
|
|
|
180
|
|
|
</code></pre>
|
|
|
<p>不过请务必记住有效的 Unicode 标量值可能会由不止一个字节组成。</p>
|
|
|
<p>从字符串中获取如同天城文这样的字形簇是很复杂的,所以标准库并没有提供这个功能。<a href="https://crates.io/">crates.io</a><!-- ignore --> 上有些提供这样功能的 crate。</p>
|
|
|
<h3 id="字符串并不简单"><a class="header" href="#字符串并不简单">字符串并不简单</a></h3>
|
|
|
<p>总而言之,字符串还是很复杂的。不同的语言选择了不同的向程序员展示其复杂性的方式。Rust 选择了以准确的方式处理 <code>String</code> 数据作为所有 Rust 程序的默认行为,这意味着程序员们必须更多的思考如何预先处理 UTF-8 数据。这种权衡相比其他语言更多地暴露出了字符串的复杂性,不过也使你在开发周期后期免于处理涉及非 ASCII 字符的错误。</p>
|
|
|
<p>好消息是标准库提供了很多围绕 <code>String</code> 和 <code>&str</code> 构建的功能,来帮助我们正确处理这些复杂场景。请务必查看这些使用方法的文档,例如 <code>contains</code> 来搜索一个字符串,和 <code>replace</code> 将字符串的一部分替换为另一个字符串。</p>
|
|
|
<p>现在让我们转向一些不太复杂的集合:哈希 map!</p>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
|
<!-- Mobile navigation buttons -->
|
|
|
<a rel="prev" href="ch08-01-vectors.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="ch08-03-hash-maps.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="ch08-01-vectors.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="ch08-03-hash-maps.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>
|