build: 2026-06-22
This commit is contained in:
801
build/ch09-02-recoverable-errors-with-result.html
Normal file
801
build/ch09-02-recoverable-errors-with-result.html
Normal file
@@ -0,0 +1,801 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Recoverable Errors with Result - The Rust Programming Language</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-0392ca55.css">
|
||||
<link rel="stylesheet" href="css/chrome-fc474251.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-6a1da8cc.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-0e4ce700.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">The Rust Programming Language</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/rust-lang/book" 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="recoverable-errors-with-result"><a class="header" href="#recoverable-errors-with-result">Recoverable Errors with <code>Result</code></a></h2>
|
||||
<p>Most errors aren’t serious enough to require the program to stop entirely.
|
||||
Sometimes when a function fails, it’s for a reason that you can easily interpret
|
||||
and respond to. For example, if you try to open a file and that operation fails
|
||||
because the file doesn’t exist, you might want to create the file instead of
|
||||
terminating the process.</p>
|
||||
<p>Recall from <a href="ch02-00-guessing-game-tutorial.html#handling-potential-failure-with-result">“Handling Potential Failure with <code>Result</code>”</a><!--
|
||||
ignore --> in Chapter 2 that the <code>Result</code> enum is defined as having two
|
||||
variants, <code>Ok</code> and <code>Err</code>, as follows:</p>
|
||||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
||||
</span><span class="boring">fn main() {
|
||||
</span>enum Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E),
|
||||
}
|
||||
<span class="boring">}</span></code></pre>
|
||||
<p>The <code>T</code> and <code>E</code> are generic type parameters: We’ll discuss generics in more
|
||||
detail in Chapter 10. What you need to know right now is that <code>T</code> represents
|
||||
the type of the value that will be returned in a success case within the <code>Ok</code>
|
||||
variant, and <code>E</code> represents the type of the error that will be returned in a
|
||||
failure case within the <code>Err</code> variant. Because <code>Result</code> has these generic type
|
||||
parameters, we can use the <code>Result</code> type and the functions defined on it in
|
||||
many different situations where the success value and error value we want to
|
||||
return may differ.</p>
|
||||
<p>Let’s call a function that returns a <code>Result</code> value because the function could
|
||||
fail. In Listing 9-3, we try to open a file.</p>
|
||||
<figure class="listing" id="listing-9-3">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre class="playground"><code class="language-rust edition2024">use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let greeting_file_result = File::open("hello.txt");
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-9-3">Listing 9-3</a>: Opening a file</figcaption>
|
||||
</figure>
|
||||
<p>The return type of <code>File::open</code> is a <code>Result<T, E></code>. The generic parameter <code>T</code>
|
||||
has been filled in by the implementation of <code>File::open</code> with the type of the
|
||||
success value, <code>std::fs::File</code>, which is a file handle. The type of <code>E</code> used in
|
||||
the error value is <code>std::io::Error</code>. This return type means the call to
|
||||
<code>File::open</code> might succeed and return a file handle that we can read from or
|
||||
write to. The function call also might fail: For example, the file might not
|
||||
exist, or we might not have permission to access the file. The <code>File::open</code>
|
||||
function needs to have a way to tell us whether it succeeded or failed and at
|
||||
the same time give us either the file handle or error information. This
|
||||
information is exactly what the <code>Result</code> enum conveys.</p>
|
||||
<p>In the case where <code>File::open</code> succeeds, the value in the variable
|
||||
<code>greeting_file_result</code> will be an instance of <code>Ok</code> that contains a file handle.
|
||||
In the case where it fails, the value in <code>greeting_file_result</code> will be an
|
||||
instance of <code>Err</code> that contains more information about the kind of error that
|
||||
occurred.</p>
|
||||
<p>We need to add to the code in Listing 9-3 to take different actions depending
|
||||
on the value <code>File::open</code> returns. Listing 9-4 shows one way to handle the
|
||||
<code>Result</code> using a basic tool, the <code>match</code> expression that we discussed in
|
||||
Chapter 6.</p>
|
||||
<figure class="listing" id="listing-9-4">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre class="playground"><code class="language-rust should_panic edition2024">use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let greeting_file_result = File::open("hello.txt");
|
||||
|
||||
let greeting_file = match greeting_file_result {
|
||||
Ok(file) => file,
|
||||
Err(error) => panic!("Problem opening the file: {error:?}"),
|
||||
};
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-9-4">Listing 9-4</a>: Using a <code>match</code> expression to handle the <code>Result</code> variants that might be returned</figcaption>
|
||||
</figure>
|
||||
<p>Note that, like the <code>Option</code> enum, the <code>Result</code> enum and its variants have been
|
||||
brought into scope by the prelude, so we don’t need to specify <code>Result::</code>
|
||||
before the <code>Ok</code> and <code>Err</code> variants in the <code>match</code> arms.</p>
|
||||
<p>When the result is <code>Ok</code>, this code will return the inner <code>file</code> value out of
|
||||
the <code>Ok</code> variant, and we then assign that file handle value to the variable
|
||||
<code>greeting_file</code>. After the <code>match</code>, we can use the file handle for reading or
|
||||
writing.</p>
|
||||
<p>The other arm of the <code>match</code> handles the case where we get an <code>Err</code> value from
|
||||
<code>File::open</code>. In this example, we’ve chosen to call the <code>panic!</code> macro. If
|
||||
there’s no file named <em>hello.txt</em> in our current directory and we run this
|
||||
code, we’ll see the following output from the <code>panic!</code> macro:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling error-handling v0.1.0 (file:///projects/error-handling)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
|
||||
Running `target/debug/error-handling`
|
||||
|
||||
thread 'main' panicked at src/main.rs:8:23:
|
||||
Problem opening the file: Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
</code></pre>
|
||||
<p>As usual, this output tells us exactly what has gone wrong.</p>
|
||||
<h3 id="matching-on-different-errors"><a class="header" href="#matching-on-different-errors">Matching on Different Errors</a></h3>
|
||||
<p>The code in Listing 9-4 will <code>panic!</code> no matter why <code>File::open</code> failed.
|
||||
However, we want to take different actions for different failure reasons. If
|
||||
<code>File::open</code> failed because the file doesn’t exist, we want to create the file
|
||||
and return the handle to the new file. If <code>File::open</code> failed for any other
|
||||
reason—for example, because we didn’t have permission to open the file—we still
|
||||
want the code to <code>panic!</code> in the same way it did in Listing 9-4. For this, we
|
||||
add an inner <code>match</code> expression, shown in Listing 9-5.</p>
|
||||
<figure class="listing" id="listing-9-5">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<!-- ignore this test because otherwise it creates hello.txt which causes other
|
||||
tests to fail lol -->
|
||||
<pre><code class="language-rust ignore">use std::fs::File;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
fn main() {
|
||||
let greeting_file_result = File::open("hello.txt");
|
||||
|
||||
let greeting_file = match greeting_file_result {
|
||||
Ok(file) => file,
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::NotFound => match File::create("hello.txt") {
|
||||
Ok(fc) => fc,
|
||||
Err(e) => panic!("Problem creating the file: {e:?}"),
|
||||
},
|
||||
_ => {
|
||||
panic!("Problem opening the file: {error:?}");
|
||||
}
|
||||
},
|
||||
};
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-9-5">Listing 9-5</a>: Handling different kinds of errors in different ways</figcaption>
|
||||
</figure>
|
||||
<p>The type of the value that <code>File::open</code> returns inside the <code>Err</code> variant is
|
||||
<code>io::Error</code>, which is a struct provided by the standard library. This struct
|
||||
has a method, <code>kind</code>, that we can call to get an <code>io::ErrorKind</code> value. The
|
||||
enum <code>io::ErrorKind</code> is provided by the standard library and has variants
|
||||
representing the different kinds of errors that might result from an <code>io</code>
|
||||
operation. The variant we want to use is <code>ErrorKind::NotFound</code>, which indicates
|
||||
the file we’re trying to open doesn’t exist yet. So, we match on
|
||||
<code>greeting_file_result</code>, but we also have an inner match on <code>error.kind()</code>.</p>
|
||||
<p>The condition we want to check in the inner match is whether the value returned
|
||||
by <code>error.kind()</code> is the <code>NotFound</code> variant of the <code>ErrorKind</code> enum. If it is,
|
||||
we try to create the file with <code>File::create</code>. However, because <code>File::create</code>
|
||||
could also fail, we need a second arm in the inner <code>match</code> expression. When the
|
||||
file can’t be created, a different error message is printed. The second arm of
|
||||
the outer <code>match</code> stays the same, so the program panics on any error besides
|
||||
the missing file error.</p>
|
||||
<section class="note" aria-role="note">
|
||||
<h4 id="alternatives-to-using-match-with-resultt-e"><a class="header" href="#alternatives-to-using-match-with-resultt-e">Alternatives to Using <code>match</code> with <code>Result<T, E></code></a></h4>
|
||||
<p>That’s a lot of <code>match</code>! The <code>match</code> expression is very useful but also very
|
||||
much a primitive. In Chapter 13, you’ll learn about closures, which are used
|
||||
with many of the methods defined on <code>Result<T, E></code>. These methods can be more
|
||||
concise than using <code>match</code> when handling <code>Result<T, E></code> values in your code.</p>
|
||||
<p>For example, here’s another way to write the same logic as shown in Listing
|
||||
9-5, this time using closures and the <code>unwrap_or_else</code> method:</p>
|
||||
<!-- CAN'T EXTRACT SEE https://github.com/rust-lang/mdBook/issues/1127 -->
|
||||
<pre><code class="language-rust ignore">use std::fs::File;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
fn main() {
|
||||
let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
|
||||
if error.kind() == ErrorKind::NotFound {
|
||||
File::create("hello.txt").unwrap_or_else(|error| {
|
||||
panic!("Problem creating the file: {error:?}");
|
||||
})
|
||||
} else {
|
||||
panic!("Problem opening the file: {error:?}");
|
||||
}
|
||||
});
|
||||
}</code></pre>
|
||||
<p>Although this code has the same behavior as Listing 9-5, it doesn’t contain
|
||||
any <code>match</code> expressions and is cleaner to read. Come back to this example
|
||||
after you’ve read Chapter 13 and look up the <code>unwrap_or_else</code> method in the
|
||||
standard library documentation. Many more of these methods can clean up huge,
|
||||
nested <code>match</code> expressions when you’re dealing with errors.</p>
|
||||
</section>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="shortcuts-for-panic-on-error-unwrap-and-expect"></a></p>
|
||||
<h4 id="shortcuts-for-panic-on-error"><a class="header" href="#shortcuts-for-panic-on-error">Shortcuts for Panic on Error</a></h4>
|
||||
<p>Using <code>match</code> works well enough, but it can be a bit verbose and doesn’t always
|
||||
communicate intent well. The <code>Result<T, E></code> type has many helper methods
|
||||
defined on it to do various, more specific tasks. The <code>unwrap</code> method is a
|
||||
shortcut method implemented just like the <code>match</code> expression we wrote in
|
||||
Listing 9-4. If the <code>Result</code> value is the <code>Ok</code> variant, <code>unwrap</code> will return
|
||||
the value inside the <code>Ok</code>. If the <code>Result</code> is the <code>Err</code> variant, <code>unwrap</code> will
|
||||
call the <code>panic!</code> macro for us. Here is an example of <code>unwrap</code> in action:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre class="playground"><code class="language-rust should_panic edition2024">use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let greeting_file = File::open("hello.txt").unwrap();
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>If we run this code without a <em>hello.txt</em> file, we’ll see an error message from
|
||||
the <code>panic!</code> call that the <code>unwrap</code> method makes:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch09-error-handling/no-listing-04-unwrap
|
||||
cargo run
|
||||
copy and paste relevant text
|
||||
-->
|
||||
<pre><code class="language-text">thread 'main' panicked at src/main.rs:4:49:
|
||||
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||
</code></pre>
|
||||
<p>Similarly, the <code>expect</code> method lets us also choose the <code>panic!</code> error message.
|
||||
Using <code>expect</code> instead of <code>unwrap</code> and providing good error messages can convey
|
||||
your intent and make tracking down the source of a panic easier. The syntax of
|
||||
<code>expect</code> looks like this:</p>
|
||||
<figure class="listing">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre class="playground"><code class="language-rust should_panic edition2024">use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let greeting_file = File::open("hello.txt")
|
||||
.expect("hello.txt should be included in this project");
|
||||
}</code></pre>
|
||||
</figure>
|
||||
<p>We use <code>expect</code> in the same way as <code>unwrap</code>: to return the file handle or call
|
||||
the <code>panic!</code> macro. The error message used by <code>expect</code> in its call to <code>panic!</code>
|
||||
will be the parameter that we pass to <code>expect</code>, rather than the default
|
||||
<code>panic!</code> message that <code>unwrap</code> uses. Here’s what it looks like:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch09-error-handling/no-listing-05-expect
|
||||
cargo run
|
||||
copy and paste relevant text
|
||||
-->
|
||||
<pre><code class="language-text">thread 'main' panicked at src/main.rs:5:10:
|
||||
hello.txt should be included in this project: Os { code: 2, kind: NotFound, message: "No such file or directory" }
|
||||
</code></pre>
|
||||
<p>In production-quality code, most Rustaceans choose <code>expect</code> rather than
|
||||
<code>unwrap</code> and give more context about why the operation is expected to always
|
||||
succeed. That way, if your assumptions are ever proven wrong, you have more
|
||||
information to use in debugging.</p>
|
||||
<h3 id="propagating-errors"><a class="header" href="#propagating-errors">Propagating Errors</a></h3>
|
||||
<p>When a function’s implementation calls something that might fail, instead of
|
||||
handling the error within the function itself, you can return the error to the
|
||||
calling code so that it can decide what to do. This is known as <em>propagating</em>
|
||||
the error and gives more control to the calling code, where there might be more
|
||||
information or logic that dictates how the error should be handled than what
|
||||
you have available in the context of your code.</p>
|
||||
<p>For example, Listing 9-6 shows a function that reads a username from a file. If
|
||||
the file doesn’t exist or can’t be read, this function will return those errors
|
||||
to the code that called the function.</p>
|
||||
<figure class="listing" id="listing-9-6">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<!-- Deliberately not using rustdoc_include here; the `main` function in the
|
||||
file panics. We do want to include it for reader experimentation purposes, but
|
||||
don't want to include it for rustdoc testing purposes. -->
|
||||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
||||
</span><span class="boring">fn main() {
|
||||
</span>use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
let username_file_result = File::open("hello.txt");
|
||||
|
||||
let mut username_file = match username_file_result {
|
||||
Ok(file) => file,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let mut username = String::new();
|
||||
|
||||
match username_file.read_to_string(&mut username) {
|
||||
Ok(_) => Ok(username),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
<span class="boring">}</span></code></pre>
|
||||
<figcaption><a href="#listing-9-6">Listing 9-6</a>: A function that returns errors to the calling code using <code>match</code></figcaption>
|
||||
</figure>
|
||||
<p>This function can be written in a much shorter way, but we’re going to start by
|
||||
doing a lot of it manually in order to explore error handling; at the end,
|
||||
we’ll show the shorter way. Let’s look at the return type of the function
|
||||
first: <code>Result<String, io::Error></code>. This means the function is returning a
|
||||
value of the type <code>Result<T, E></code>, where the generic parameter <code>T</code> has been
|
||||
filled in with the concrete type <code>String</code> and the generic type <code>E</code> has been
|
||||
filled in with the concrete type <code>io::Error</code>.</p>
|
||||
<p>If this function succeeds without any problems, the code that calls this
|
||||
function will receive an <code>Ok</code> value that holds a <code>String</code>—the <code>username</code> that
|
||||
this function read from the file. If this function encounters any problems, the
|
||||
calling code will receive an <code>Err</code> value that holds an instance of <code>io::Error</code>
|
||||
that contains more information about what the problems were. We chose
|
||||
<code>io::Error</code> as the return type of this function because that happens to be the
|
||||
type of the error value returned from both of the operations we’re calling in
|
||||
this function’s body that might fail: the <code>File::open</code> function and the
|
||||
<code>read_to_string</code> method.</p>
|
||||
<p>The body of the function starts by calling the <code>File::open</code> function. Then, we
|
||||
handle the <code>Result</code> value with a <code>match</code> similar to the <code>match</code> in Listing 9-4.
|
||||
If <code>File::open</code> succeeds, the file handle in the pattern variable <code>file</code>
|
||||
becomes the value in the mutable variable <code>username_file</code> and the function
|
||||
continues. In the <code>Err</code> case, instead of calling <code>panic!</code>, we use the <code>return</code>
|
||||
keyword to return early out of the function entirely and pass the error value
|
||||
from <code>File::open</code>, now in the pattern variable <code>e</code>, back to the calling code as
|
||||
this function’s error value.</p>
|
||||
<p>So, if we have a file handle in <code>username_file</code>, the function then creates a
|
||||
new <code>String</code> in variable <code>username</code> and calls the <code>read_to_string</code> method on
|
||||
the file handle in <code>username_file</code> to read the contents of the file into
|
||||
<code>username</code>. The <code>read_to_string</code> method also returns a <code>Result</code> because it
|
||||
might fail, even though <code>File::open</code> succeeded. So, we need another <code>match</code> to
|
||||
handle that <code>Result</code>: If <code>read_to_string</code> succeeds, then our function has
|
||||
succeeded, and we return the username from the file that’s now in <code>username</code>
|
||||
wrapped in an <code>Ok</code>. If <code>read_to_string</code> fails, we return the error value in the
|
||||
same way that we returned the error value in the <code>match</code> that handled the
|
||||
return value of <code>File::open</code>. However, we don’t need to explicitly say
|
||||
<code>return</code>, because this is the last expression in the function.</p>
|
||||
<p>The code that calls this code will then handle getting either an <code>Ok</code> value
|
||||
that contains a username or an <code>Err</code> value that contains an <code>io::Error</code>. It’s
|
||||
up to the calling code to decide what to do with those values. If the calling
|
||||
code gets an <code>Err</code> value, it could call <code>panic!</code> and crash the program, use a
|
||||
default username, or look up the username from somewhere other than a file, for
|
||||
example. We don’t have enough information on what the calling code is actually
|
||||
trying to do, so we propagate all the success or error information upward for
|
||||
it to handle appropriately.</p>
|
||||
<p>This pattern of propagating errors is so common in Rust that Rust provides the
|
||||
question mark operator <code>?</code> to make this easier.</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="a-shortcut-for-propagating-errors-the--operator"></a></p>
|
||||
<h4 id="the--operator-shortcut"><a class="header" href="#the--operator-shortcut">The <code>?</code> Operator Shortcut</a></h4>
|
||||
<p>Listing 9-7 shows an implementation of <code>read_username_from_file</code> that has the
|
||||
same functionality as in Listing 9-6, but this implementation uses the <code>?</code>
|
||||
operator.</p>
|
||||
<figure class="listing" id="listing-9-7">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<!-- Deliberately not using rustdoc_include here; the `main` function in the
|
||||
file panics. We do want to include it for reader experimentation purposes, but
|
||||
don't want to include it for rustdoc testing purposes. -->
|
||||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
||||
</span><span class="boring">fn main() {
|
||||
</span>use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
let mut username_file = File::open("hello.txt")?;
|
||||
let mut username = String::new();
|
||||
username_file.read_to_string(&mut username)?;
|
||||
Ok(username)
|
||||
}
|
||||
<span class="boring">}</span></code></pre>
|
||||
<figcaption><a href="#listing-9-7">Listing 9-7</a>: A function that returns errors to the calling code using the <code>?</code> operator</figcaption>
|
||||
</figure>
|
||||
<p>The <code>?</code> placed after a <code>Result</code> value is defined to work in almost the same way
|
||||
as the <code>match</code> expressions that we defined to handle the <code>Result</code> values in
|
||||
Listing 9-6. If the value of the <code>Result</code> is an <code>Ok</code>, the value inside the <code>Ok</code>
|
||||
will get returned from this expression, and the program will continue. If the
|
||||
value is an <code>Err</code>, the <code>Err</code> will be returned from the whole function as if we
|
||||
had used the <code>return</code> keyword so that the error value gets propagated to the
|
||||
calling code.</p>
|
||||
<p>There is a difference between what the <code>match</code> expression from Listing 9-6 does
|
||||
and what the <code>?</code> operator does: Error values that have the <code>?</code> operator called
|
||||
on them go through the <code>from</code> function, defined in the <code>From</code> trait in the
|
||||
standard library, which is used to convert values from one type into another.
|
||||
When the <code>?</code> operator calls the <code>from</code> function, the error type received is
|
||||
converted into the error type defined in the return type of the current
|
||||
function. This is useful when a function returns one error type to represent
|
||||
all the ways a function might fail, even if parts might fail for many different
|
||||
reasons.</p>
|
||||
<p>For example, we could change the <code>read_username_from_file</code> function in Listing
|
||||
9-7 to return a custom error type named <code>OurError</code> that we define. If we also
|
||||
define <code>impl From<io::Error> for OurError</code> to construct an instance of
|
||||
<code>OurError</code> from an <code>io::Error</code>, then the <code>?</code> operator calls in the body of
|
||||
<code>read_username_from_file</code> will call <code>from</code> and convert the error types without
|
||||
needing to add any more code to the function.</p>
|
||||
<p>In the context of Listing 9-7, the <code>?</code> at the end of the <code>File::open</code> call will
|
||||
return the value inside an <code>Ok</code> to the variable <code>username_file</code>. If an error
|
||||
occurs, the <code>?</code> operator will return early out of the whole function and give
|
||||
any <code>Err</code> value to the calling code. The same thing applies to the <code>?</code> at the
|
||||
end of the <code>read_to_string</code> call.</p>
|
||||
<p>The <code>?</code> operator eliminates a lot of boilerplate and makes this function’s
|
||||
implementation simpler. We could even shorten this code further by chaining
|
||||
method calls immediately after the <code>?</code>, as shown in Listing 9-8.</p>
|
||||
<figure class="listing" id="listing-9-8">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<!-- Deliberately not using rustdoc_include here; the `main` function in the
|
||||
file panics. We do want to include it for reader experimentation purposes, but
|
||||
don't want to include it for rustdoc testing purposes. -->
|
||||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
||||
</span><span class="boring">fn main() {
|
||||
</span>use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
let mut username = String::new();
|
||||
|
||||
File::open("hello.txt")?.read_to_string(&mut username)?;
|
||||
|
||||
Ok(username)
|
||||
}
|
||||
<span class="boring">}</span></code></pre>
|
||||
<figcaption><a href="#listing-9-8">Listing 9-8</a>: Chaining method calls after the <code>?</code> operator</figcaption>
|
||||
</figure>
|
||||
<p>We’ve moved the creation of the new <code>String</code> in <code>username</code> to the beginning of
|
||||
the function; that part hasn’t changed. Instead of creating a variable
|
||||
<code>username_file</code>, we’ve chained the call to <code>read_to_string</code> directly onto the
|
||||
result of <code>File::open("hello.txt")?</code>. We still have a <code>?</code> at the end of the
|
||||
<code>read_to_string</code> call, and we still return an <code>Ok</code> value containing <code>username</code>
|
||||
when both <code>File::open</code> and <code>read_to_string</code> succeed rather than returning
|
||||
errors. The functionality is again the same as in Listing 9-6 and Listing 9-7;
|
||||
this is just a different, more ergonomic way to write it.</p>
|
||||
<p>Listing 9-9 shows a way to make this even shorter using <code>fs::read_to_string</code>.</p>
|
||||
<figure class="listing" id="listing-9-9">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<!-- Deliberately not using rustdoc_include here; the `main` function in the
|
||||
file panics. We do want to include it for reader experimentation purposes, but
|
||||
don't want to include it for rustdoc testing purposes. -->
|
||||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
|
||||
</span><span class="boring">fn main() {
|
||||
</span>use std::fs;
|
||||
use std::io;
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
fs::read_to_string("hello.txt")
|
||||
}
|
||||
<span class="boring">}</span></code></pre>
|
||||
<figcaption><a href="#listing-9-9">Listing 9-9</a>: Using <code>fs::read_to_string</code> instead of opening and then reading the file</figcaption>
|
||||
</figure>
|
||||
<p>Reading a file into a string is a fairly common operation, so the standard
|
||||
library provides the convenient <code>fs::read_to_string</code> function that opens the
|
||||
file, creates a new <code>String</code>, reads the contents of the file, puts the contents
|
||||
into that <code>String</code>, and returns it. Of course, using <code>fs::read_to_string</code>
|
||||
doesn’t give us the opportunity to explain all the error handling, so we did it
|
||||
the longer way first.</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="where-the--operator-can-be-used"></a></p>
|
||||
<h4 id="where-to-use-the--operator"><a class="header" href="#where-to-use-the--operator">Where to Use the <code>?</code> Operator</a></h4>
|
||||
<p>The <code>?</code> operator can only be used in functions whose return type is compatible
|
||||
with the value the <code>?</code> is used on. This is because the <code>?</code> operator is defined
|
||||
to perform an early return of a value out of the function, in the same manner
|
||||
as the <code>match</code> expression we defined in Listing 9-6. In Listing 9-6, the
|
||||
<code>match</code> was using a <code>Result</code> value, and the early return arm returned an
|
||||
<code>Err(e)</code> value. The return type of the function has to be a <code>Result</code> so that
|
||||
it’s compatible with this <code>return</code>.</p>
|
||||
<p>In Listing 9-10, let’s look at the error we’ll get if we use the <code>?</code> operator
|
||||
in a <code>main</code> function with a return type that is incompatible with the type of
|
||||
the value we use <code>?</code> on.</p>
|
||||
<figure class="listing" id="listing-9-10">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile">use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let greeting_file = File::open("hello.txt")?;
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-9-10">Listing 9-10</a>: Attempting to use the <code>?</code> in the <code>main</code> function that returns <code>()</code> won’t compile.</figcaption>
|
||||
</figure>
|
||||
<p>This code opens a file, which might fail. The <code>?</code> operator follows the <code>Result</code>
|
||||
value returned by <code>File::open</code>, but this <code>main</code> function has the return type of
|
||||
<code>()</code>, not <code>Result</code>. When we compile this code, we get the following error
|
||||
message:</p>
|
||||
<pre><code class="language-console">$ cargo run
|
||||
Compiling error-handling v0.1.0 (file:///projects/error-handling)
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> src/main.rs:4:48
|
||||
|
|
||||
3 | fn main() {
|
||||
| --------- this function should return `Result` or `Option` to accept `?`
|
||||
4 | let greeting_file = File::open("hello.txt")?;
|
||||
| ^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
help: consider adding return type
|
||||
|
|
||||
3 ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
4 | let greeting_file = File::open("hello.txt")?;
|
||||
5 + Ok(())
|
||||
|
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error: could not compile `error-handling` (bin "error-handling") due to 1 previous error
|
||||
</code></pre>
|
||||
<p>This error points out that we’re only allowed to use the <code>?</code> operator in a
|
||||
function that returns <code>Result</code>, <code>Option</code>, or another type that implements
|
||||
<code>FromResidual</code>.</p>
|
||||
<p>To fix the error, you have two choices. One choice is to change the return type
|
||||
of your function to be compatible with the value you’re using the <code>?</code> operator
|
||||
on as long as you have no restrictions preventing that. The other choice is to
|
||||
use a <code>match</code> or one of the <code>Result<T, E></code> methods to handle the <code>Result<T, E></code>
|
||||
in whatever way is appropriate.</p>
|
||||
<p>The error message also mentioned that <code>?</code> can be used with <code>Option<T></code> values
|
||||
as well. As with using <code>?</code> on <code>Result</code>, you can only use <code>?</code> on <code>Option</code> in a
|
||||
function that returns an <code>Option</code>. The behavior of the <code>?</code> operator when called
|
||||
on an <code>Option<T></code> is similar to its behavior when called on a <code>Result<T, E></code>:
|
||||
If the value is <code>None</code>, the <code>None</code> will be returned early from the function at
|
||||
that point. If the value is <code>Some</code>, the value inside the <code>Some</code> is the
|
||||
resultant value of the expression, and the function continues. Listing 9-11 has
|
||||
an example of a function that finds the last character of the first line in the
|
||||
given text.</p>
|
||||
<figure class="listing" id="listing-9-11">
|
||||
<pre class="playground"><code class="language-rust edition2024">fn last_char_of_first_line(text: &str) -> Option<char> {
|
||||
text.lines().next()?.chars().last()
|
||||
}
|
||||
<span class="boring">
|
||||
</span><span class="boring">fn main() {
|
||||
</span><span class="boring"> assert_eq!(
|
||||
</span><span class="boring"> last_char_of_first_line("Hello, world\nHow are you today?"),
|
||||
</span><span class="boring"> Some('d')
|
||||
</span><span class="boring"> );
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> assert_eq!(last_char_of_first_line(""), None);
|
||||
</span><span class="boring"> assert_eq!(last_char_of_first_line("\nhi"), None);
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<figcaption><a href="#listing-9-11">Listing 9-11</a>: Using the <code>?</code> operator on an <code>Option<T></code> value</figcaption>
|
||||
</figure>
|
||||
<p>This function returns <code>Option<char></code> because it’s possible that there is a
|
||||
character there, but it’s also possible that there isn’t. This code takes the
|
||||
<code>text</code> string slice argument and calls the <code>lines</code> method on it, which returns
|
||||
an iterator over the lines in the string. Because this function wants to
|
||||
examine the first line, it calls <code>next</code> on the iterator to get the first value
|
||||
from the iterator. If <code>text</code> is the empty string, this call to <code>next</code> will
|
||||
return <code>None</code>, in which case we use <code>?</code> to stop and return <code>None</code> from
|
||||
<code>last_char_of_first_line</code>. If <code>text</code> is not the empty string, <code>next</code> will
|
||||
return a <code>Some</code> value containing a string slice of the first line in <code>text</code>.</p>
|
||||
<p>The <code>?</code> extracts the string slice, and we can call <code>chars</code> on that string slice
|
||||
to get an iterator of its characters. We’re interested in the last character in
|
||||
this first line, so we call <code>last</code> to return the last item in the iterator.
|
||||
This is an <code>Option</code> because it’s possible that the first line is the empty
|
||||
string; for example, if <code>text</code> starts with a blank line but has characters on
|
||||
other lines, as in <code>"\nhi"</code>. However, if there is a last character on the first
|
||||
line, it will be returned in the <code>Some</code> variant. The <code>?</code> operator in the middle
|
||||
gives us a concise way to express this logic, allowing us to implement the
|
||||
function in one line. If we couldn’t use the <code>?</code> operator on <code>Option</code>, we’d
|
||||
have to implement this logic using more method calls or a <code>match</code> expression.</p>
|
||||
<p>Note that you can use the <code>?</code> operator on a <code>Result</code> in a function that returns
|
||||
<code>Result</code>, and you can use the <code>?</code> operator on an <code>Option</code> in a function that
|
||||
returns <code>Option</code>, but you can’t mix and match. The <code>?</code> operator won’t
|
||||
automatically convert a <code>Result</code> to an <code>Option</code> or vice versa; in those cases,
|
||||
you can use methods like the <code>ok</code> method on <code>Result</code> or the <code>ok_or</code> method on
|
||||
<code>Option</code> to do the conversion explicitly.</p>
|
||||
<p>So far, all the <code>main</code> functions we’ve used return <code>()</code>. The <code>main</code> function is
|
||||
special because it’s the entry point and exit point of an executable program,
|
||||
and there are restrictions on what its return type can be for the program to
|
||||
behave as expected.</p>
|
||||
<p>Luckily, <code>main</code> can also return a <code>Result<(), E></code>. Listing 9-12 has the code
|
||||
from Listing 9-10, but we’ve changed the return type of <code>main</code> to be
|
||||
<code>Result<(), Box<dyn Error>></code> and added a return value <code>Ok(())</code> to the end. This
|
||||
code will now compile.</p>
|
||||
<figure class="listing" id="listing-9-12">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use std::error::Error;
|
||||
use std::fs::File;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let greeting_file = File::open("hello.txt")?;
|
||||
|
||||
Ok(())
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-9-12">Listing 9-12</a>: Changing <code>main</code> to return <code>Result<(), E></code> allows the use of the <code>?</code> operator on <code>Result</code> values.</figcaption>
|
||||
</figure>
|
||||
<p>The <code>Box<dyn Error></code> type is a trait object, which we’ll talk about in <a href="ch18-02-trait-objects.html#using-trait-objects-to-abstract-over-shared-behavior">“Using
|
||||
Trait Objects to Abstract over Shared Behavior”</a><!-- ignore -->
|
||||
in Chapter 18. For now, you can read <code>Box<dyn Error></code> to mean “any kind of
|
||||
error.” Using <code>?</code> on a <code>Result</code> value in a <code>main</code> function with the error type
|
||||
<code>Box<dyn Error></code> is allowed because it allows any <code>Err</code> value to be returned
|
||||
early. Even though the body of this <code>main</code> function will only ever return
|
||||
errors of type <code>std::io::Error</code>, by specifying <code>Box<dyn Error></code>, this signature
|
||||
will continue to be correct even if more code that returns other errors is
|
||||
added to the body of <code>main</code>.</p>
|
||||
<p>When a <code>main</code> function returns a <code>Result<(), E></code>, the executable will exit with
|
||||
a value of <code>0</code> if <code>main</code> returns <code>Ok(())</code> and will exit with a nonzero value if
|
||||
<code>main</code> returns an <code>Err</code> value. Executables written in C return integers when
|
||||
they exit: Programs that exit successfully return the integer <code>0</code>, and programs
|
||||
that error return some integer other than <code>0</code>. Rust also returns integers from
|
||||
executables to be compatible with this convention.</p>
|
||||
<p>The <code>main</code> function may return any types that implement <a href="../std/process/trait.Termination.html">the
|
||||
<code>std::process::Termination</code> trait</a><!-- ignore -->, which contains
|
||||
a function <code>report</code> that returns an <code>ExitCode</code>. Consult the standard library
|
||||
documentation for more information on implementing the <code>Termination</code> trait for
|
||||
your own types.</p>
|
||||
<p>Now that we’ve discussed the details of calling <code>panic!</code> or returning <code>Result</code>,
|
||||
let’s return to the topic of how to decide which is appropriate to use in which
|
||||
cases.</p>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="ch09-01-unrecoverable-errors-with-panic.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="ch09-03-to-panic-or-not-to-panic.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="ch09-01-unrecoverable-errors-with-panic.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="ch09-03-to-panic-or-not-to-panic.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-09f2665d.js"></script>
|
||||
|
||||
<script src="clipboard-1626706a.min.js"></script>
|
||||
<script src="highlight-abc7f01d.js"></script>
|
||||
<script src="book-c22b7243.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
<script src="ferris-2317480c.js"></script>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user