Files
rust-by-practice/collections/string.html
sunface 987c59ed75 deploy
2025-04-25 12:48:03 +08:00

411 lines
18 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>String - Rust By Practice</title>
<!-- Custom HTML head -->
<meta name="description" content="Learn Rust with Example, Exercise and real Practice, written with ❤️ by https://course.rs team">
<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" id="highlight-css" href="../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../theme/style1.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="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="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("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 = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="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="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</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">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<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="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</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 By Practice</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-by-practice" 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-by-practice/edit/master/en/src/collections/string.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>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="string"><a class="header" href="#string">String</a></h1>
<p><code>std::string::String</code> is a UTF-8 encoded, growable string. It is the most common string type we used in daily development, it also has ownership over the string contents.</p>
<h3 id="basic-operations"><a class="header" href="#basic-operations">Basic operations</a></h3>
<ol>
<li>🌟🌟</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
// FILL in the blanks and FIX errors
// 1. Don't use `to_string()`
// 2. Don't add/remove any code line
fn main() {
let mut s: String = "hello, ";
s.push_str("world".to_string());
s.push(__);
move_ownership(s);
assert_eq!(s, "hello, world!");
println!("Success!");
}
fn move_ownership(s: String) {
println!("ownership of \"{}\" is moved here!", s)
}</code></pre></pre>
<h3 id="string-and-str"><a class="header" href="#string-and-str">String and &amp;str</a></h3>
<p>A <code>String</code> is stored as a vector of bytes (<code>Vec&lt;u8&gt;</code>), but guaranteed to always be a valid UTF-8 sequence. <code>String</code> is heap allocated, growable and not null terminated.</p>
<p><code>&amp;str</code> is a slice (<code>&amp;[u8]</code>) that always points to a valid UTF-8 sequence, and can be used to view into a String, just like <code>&amp;[T]</code> is a view into <code>Vec&lt;T&gt;</code>.</p>
<ol start="2">
<li>🌟🌟</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">// FILL in the blanks
fn main() {
let mut s = String::from("hello, world");
let slice1: &amp;str = __; // In two ways
assert_eq!(slice1, "hello, world");
let slice2 = __;
assert_eq!(slice2, "hello");
let slice3: __ = __;
slice3.push('!');
assert_eq!(slice3, "hello, world!");
println!("Success!");
}</code></pre></pre>
<ol start="3">
<li>🌟🌟</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
// Question: how many heap allocations are happening here?
// Your answer:
fn main() {
// Create a String type based on `&amp;str`
// The type of string literals is `&amp;str`
let s: String = String::from("hello, world!");
// Create a slice point to String `s`
let slice: &amp;str = &amp;s;
// Create a String type based on the recently created slice
let s: String = slice.to_string();
assert_eq!(s, "hello, world!");
println!("Success!");
}</code></pre></pre>
<h3 id="utf-8--indexing"><a class="header" href="#utf-8--indexing">UTF-8 &amp; Indexing</a></h3>
<p>Strings are always valid UTF-8. This has a few implications:</p>
<ul>
<li>The first of which is that if you need a non-UTF-8 string, consider <a href="https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html">OsString</a>. It is similar, but without the UTF-8 constraint.</li>
<li>The second implication is that you cannot index into a String.</li>
</ul>
<p>Indexing is intended to be a constant-time operation, but UTF-8 encoding does not allow us to do this. Furthermore, its not clear what sort of thing the index should return: a byte, a codepoint, or a grapheme cluster. The bytes and chars methods return iterators over the first two, respectively.</p>
<ol start="4">
<li>🌟🌟🌟 You can't use index to access a char in a string, but you can use slice <code>&amp;s1[start..end]</code>.</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
// FILL in the blank and FIX errors
fn main() {
let s = String::from("hello, 世界");
let slice1 = s[0]; //tips: `h` only takes 1 byte in UTF8 format
assert_eq!(slice1, "h");
let slice2 = &amp;s[3..5]; // Tips: `中` takes 3 bytes in UTF8 format
assert_eq!(slice2, "世");
// Iterate through all chars in s
for (i, c) in s.__ {
if i == 7 {
assert_eq!(c, '世')
}
}
println!("Success!");
}</code></pre></pre>
<h4 id="utf8_slice"><a class="header" href="#utf8_slice">UTF8_slice</a></h4>
<p>You can use <a href="https://docs.rs/utf8_slice/1.0.0/utf8_slice/fn.slice.html">utf8_slice</a> to slice UTF8 string, it can index chars instead of bytes.</p>
<p><strong>Example</strong></p>
<pre><pre class="playground"><code class="language-rust edition2021">use utf8_slice;
fn main() {
let s = "The 🚀 goes to the 🌑!";
let rocket = utf8_slice::slice(s, 4, 5);
// Will equal "🚀"
}</code></pre></pre>
<ol start="5">
<li>🌟🌟🌟</li>
</ol>
<blockquote>
<p>Tips: maybe you need <code>from_utf8</code> method</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust editable edition2021">
// FILL in the blanks
fn main() {
let mut s = String::new();
__;
// Some bytes, in a vector
let v = vec![104, 101, 108, 108, 111];
// Turn a byte's vector into a String
let s1 = __;
assert_eq!(s, s1);
println!("Success!");
}</code></pre></pre>
<h3 id="representation"><a class="header" href="#representation">Representation</a></h3>
<p>A String is made up of three components: a pointer to some bytes, a length, and a capacity.</p>
<p>The pointer points to an internal buffer String uses to store its data. The length is the number of bytes currently stored in the buffer( always stored on the heap ), and the capacity is the size of the buffer in bytes. As such, the length will always be less than or equal to the capacity.</p>
<ol start="6">
<li>🌟🌟 If a String has enough capacity, adding elements to it will not re-allocate</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
// Modify the code below to print out:
// 25
// 25
// 25
// Here, theres no need to allocate more memory inside the loop.
fn main() {
let mut s = String::new();
println!("{}", s.capacity());
for _ in 0..2 {
s.push_str("hello");
println!("{}", s.capacity());
}
println!("Success!");
}</code></pre></pre>
<ol start="7">
<li>🌟🌟🌟</li>
</ol>
<pre><pre class="playground"><code class="language-rust editable edition2021">
// FILL in the blanks
use std::mem;
fn main() {
let story = String::from("Rust By Practice");
// Prevent automatically dropping of the String's data
let mut story = mem::ManuallyDrop::new(story);
let ptr = story.__();
let len = story.__();
let capacity = story.__();
assert_eq!(16, len);
// We can rebuild a String out of ptr, len, and capacity. This is all
// unsafe because we are responsible for making sure the components are
// valid:
let s = unsafe { String::from_raw_parts(ptr, len, capacity) };
assert_eq!(*story, s);
println!("Success!");
}</code></pre></pre>
<h3 id="common-methods"><a class="header" href="#common-methods">Common methods</a></h3>
<p>More exercises of String methods can be found <a href="../std/String.html">here</a>.</p>
<blockquote>
<p>You can find the solutions <a href="https://github.com/sunface/rust-by-practice">here</a>(under the solutions path), but only use it when you need it</p>
</blockquote>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../collections/intro.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 prefetch" href="../collections/vector.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="../collections/intro.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 prefetch" href="../collections/vector.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>
window.playground_copyable = true;
</script>
<script src="../ace.js"></script>
<script src="../editor.js"></script>
<script src="../mode-rust.js"></script>
<script src="../theme-dawn.js"></script>
<script src="../theme-tomorrow_night.js"></script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
<script src="../assets/custom3.js"></script>
<script src="../assets/lang1.js"></script>
</div>
</body>
</html>