mirror of
https://github.com/Dhghomon/easy_rust
synced 2024-11-19 15:25:37 +00:00
495 lines
33 KiB
HTML
495 lines
33 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="sidebar-visible no-js light">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title> The ? operator - Easy Rust</title>
|
|
|
|
|
|
|
|
|
|
<!-- Custom HTML head -->
|
|
|
|
|
|
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
<meta name="description" content="">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff" />
|
|
|
|
|
|
<link rel="icon" href="favicon.svg">
|
|
|
|
|
|
<link rel="shortcut icon" href="favicon.png">
|
|
|
|
<link rel="stylesheet" href="css/variables.css">
|
|
<link rel="stylesheet" href="css/general.css">
|
|
<link rel="stylesheet" href="css/chrome.css">
|
|
|
|
<link rel="stylesheet" href="css/print.css" media="print">
|
|
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
|
|
<link rel="stylesheet" href="fonts/fonts.css">
|
|
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" href="highlight.css">
|
|
<link rel="stylesheet" href="tomorrow-night.css">
|
|
<link rel="stylesheet" href="ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
|
|
</head>
|
|
<body>
|
|
<!-- Provide site root to javascript -->
|
|
<script type="text/javascript">
|
|
var path_to_root = "";
|
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
|
|
</script>
|
|
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script type="text/javascript">
|
|
try {
|
|
var theme = localStorage.getItem('mdbook-theme');
|
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script type="text/javascript">
|
|
var theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
var html = document.querySelector('html');
|
|
html.classList.remove('no-js')
|
|
html.classList.remove('light')
|
|
html.classList.add(theme);
|
|
html.classList.add('js');
|
|
</script>
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script type="text/javascript">
|
|
var html = document.querySelector('html');
|
|
var sidebar = 'hidden';
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
}
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<div class="sidebar-scrollbox">
|
|
<ol class="chapter"><li class="chapter-item expanded "><a href="Chapter_0.html"><strong aria-hidden="true">1.</strong> Update</a></li><li class="chapter-item expanded "><a href="Chapter_1.html"><strong aria-hidden="true">2.</strong> Introduction</a></li><li class="chapter-item expanded "><a href="Chapter_2.html"><strong aria-hidden="true">3.</strong> Who am I?</a></li><li class="chapter-item expanded "><a href="Chapter_3.html"><strong aria-hidden="true">4.</strong> Writing Rust in Easy English</a></li><li class="chapter-item expanded "><a href="Chapter_4.html"><strong aria-hidden="true">5.</strong> Rust Playground</a></li><li class="chapter-item expanded "><a href="Chapter_5.html"><strong aria-hidden="true">6.</strong> 🚧 and ⚠️</a></li><li class="chapter-item expanded "><a href="Chapter_6.html"><strong aria-hidden="true">7.</strong> Comments</a></li><li class="chapter-item expanded "><a href="Chapter_7.html"><strong aria-hidden="true">8.</strong> Types</a></li><li class="chapter-item expanded "><a href="Chapter_8.html"><strong aria-hidden="true">9.</strong> Type inference</a></li><li class="chapter-item expanded "><a href="Chapter_9.html"><strong aria-hidden="true">10.</strong> Printing 'hello, world!'</a></li><li class="chapter-item expanded "><a href="Chapter_10.html"><strong aria-hidden="true">11.</strong> Display and debug</a></li><li class="chapter-item expanded "><a href="Chapter_11.html"><strong aria-hidden="true">12.</strong> Mutability (changing)</a></li><li class="chapter-item expanded "><a href="Chapter_12.html"><strong aria-hidden="true">13.</strong> The stack, the heap, and pointers</a></li><li class="chapter-item expanded "><a href="Chapter_13.html"><strong aria-hidden="true">14.</strong> More about printing</a></li><li class="chapter-item expanded "><a href="Chapter_14.html"><strong aria-hidden="true">15.</strong> Strings</a></li><li class="chapter-item expanded "><a href="Chapter_15.html"><strong aria-hidden="true">16.</strong> const and static</a></li><li class="chapter-item expanded "><a href="Chapter_16.html"><strong aria-hidden="true">17.</strong> More on references</a></li><li class="chapter-item expanded "><a href="Chapter_17.html"><strong aria-hidden="true">18.</strong> Mutable references</a></li><li class="chapter-item expanded "><a href="Chapter_18.html"><strong aria-hidden="true">19.</strong> Giving references to functions</a></li><li class="chapter-item expanded "><a href="Chapter_19.html"><strong aria-hidden="true">20.</strong> Copy types</a></li><li class="chapter-item expanded "><a href="Chapter_20.html"><strong aria-hidden="true">21.</strong> Collection types</a></li><li class="chapter-item expanded "><a href="Chapter_21.html"><strong aria-hidden="true">22.</strong> Vectors</a></li><li class="chapter-item expanded "><a href="Chapter_22.html"><strong aria-hidden="true">23.</strong> Tuples</a></li><li class="chapter-item expanded "><a href="Chapter_23.html"><strong aria-hidden="true">24.</strong> Control flow</a></li><li class="chapter-item expanded "><a href="Chapter_24.html"><strong aria-hidden="true">25.</strong> Structs</a></li><li class="chapter-item expanded "><a href="Chapter_25.html"><strong aria-hidden="true">26.</strong> Enums</a></li><li class="chapter-item expanded "><a href="Chapter_26.html"><strong aria-hidden="true">27.</strong> Loops</a></li><li class="chapter-item expanded "><a href="Chapter_27.html"><strong aria-hidden="true">28.</strong> Implementing structs and enums</a></li><li class="chapter-item expanded "><a href="Chapter_28.html"><strong aria-hidden="true">29.</strong> Destructuring</a></li><li class="chapter-item expanded "><a href="Chapter_29.html"><strong aria-hidden="true">30.</strong> References and the dot operator</a></li><li class="chapter-item expanded "><a href="Chapter_30.html"><strong aria-hidden="true">31.</strong> Generics</a></li><li class="chapter-item expanded "><a href="Chapter_31.html"><strong aria-hidden="true">32.</strong> Option and Result</a></li><li class="chapter-item expanded "><a href="Chapter_32.html"><strong aria-hidden="true">33.</strong> Other collections</a></li><li class="chapter-item expanded "><a href="Chapter_33.html" class="active"><strong aria-hidden="true">34.</strong> The ? operator</a></li><li class="chapter-item expanded "><a href="Chapter_34.html"><strong aria-hidden="true">35.</strong> Traits</a></li><li class="chapter-item expanded "><a href="Chapter_35.html"><strong aria-hidden="true">36.</strong> Chaining methods</a></li><li class="chapter-item expanded "><a href="Chapter_36.html"><strong aria-hidden="true">37.</strong> Iterators</a></li><li class="chapter-item expanded "><a href="Chapter_37.html"><strong aria-hidden="true">38.</strong> Closures</a></li><li class="chapter-item expanded "><a href="Chapter_38.html"><strong aria-hidden="true">39.</strong> The dbg! macro and .inspect</a></li><li class="chapter-item expanded "><a href="Chapter_39.html"><strong aria-hidden="true">40.</strong> Types of &str</a></li><li class="chapter-item expanded "><a href="Chapter_40.html"><strong aria-hidden="true">41.</strong> Lifetimes</a></li><li class="chapter-item expanded "><a href="Chapter_41.html"><strong aria-hidden="true">42.</strong> Interior mutability</a></li><li class="chapter-item expanded "><a href="Chapter_42.html"><strong aria-hidden="true">43.</strong> Cow</a></li><li class="chapter-item expanded "><a href="Chapter_43.html"><strong aria-hidden="true">44.</strong> Type aliases</a></li><li class="chapter-item expanded "><a href="Chapter_44.html"><strong aria-hidden="true">45.</strong> The todo! macro</a></li><li class="chapter-item expanded "><a href="Chapter_45.html"><strong aria-hidden="true">46.</strong> Rc</a></li><li class="chapter-item expanded "><a href="Chapter_46.html"><strong aria-hidden="true">47.</strong> Multiple threads</a></li><li class="chapter-item expanded "><a href="Chapter_47.html"><strong aria-hidden="true">48.</strong> Closures in functions</a></li><li class="chapter-item expanded "><a href="Chapter_48.html"><strong aria-hidden="true">49.</strong> impl Trait</a></li><li class="chapter-item expanded "><a href="Chapter_49.html"><strong aria-hidden="true">50.</strong> Arc</a></li><li class="chapter-item expanded "><a href="Chapter_50.html"><strong aria-hidden="true">51.</strong> Channels</a></li><li class="chapter-item expanded "><a href="Chapter_51.html"><strong aria-hidden="true">52.</strong> Reading Rust documentation</a></li><li class="chapter-item expanded "><a href="Chapter_52.html"><strong aria-hidden="true">53.</strong> Attributes</a></li><li class="chapter-item expanded "><a href="Chapter_53.html"><strong aria-hidden="true">54.</strong> Box</a></li><li class="chapter-item expanded "><a href="Chapter_54.html"><strong aria-hidden="true">55.</strong> Box around traits</a></li><li class="chapter-item expanded "><a href="Chapter_55.html"><strong aria-hidden="true">56.</strong> Default and the builder pattern</a></li><li class="chapter-item expanded "><a href="Chapter_56.html"><strong aria-hidden="true">57.</strong> Deref and DerefMut</a></li><li class="chapter-item expanded "><a href="Chapter_57.html"><strong aria-hidden="true">58.</strong> Crates and modules</a></li><li class="chapter-item expanded "><a href="Chapter_58.html"><strong aria-hidden="true">59.</strong> Testing</a></li><li class="chapter-item expanded "><a href="Chapter_59.html"><strong aria-hidden="true">60.</strong> External crates</a></li><li class="chapter-item expanded "><a href="Chapter_60.html"><strong aria-hidden="true">61.</strong> A tour of the standard library</a></li><li class="chapter-item expanded "><a href="Chapter_61.html"><strong aria-hidden="true">62.</strong> Writing macros</a></li><li class="chapter-item expanded "><a href="Chapter_62.html"><strong aria-hidden="true">63.</strong> cargo</a></li><li class="chapter-item expanded "><a href="Chapter_63.html"><strong aria-hidden="true">64.</strong> Taking user input</a></li><li class="chapter-item expanded "><a href="Chapter_64.html"><strong aria-hidden="true">65.</strong> Using files</a></li><li class="chapter-item expanded "><a href="Chapter_65.html"><strong aria-hidden="true">66.</strong> cargo doc</a></li><li class="chapter-item expanded "><a href="Chapter_66.html"><strong aria-hidden="true">67.</strong> The end?</a></li></ol>
|
|
</div>
|
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
|
|
<div id="menu-bar-hover-placeholder"></div>
|
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
|
<div class="left-buttons">
|
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</button>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<h1 class="menu-title">Easy Rust</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>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script type="text/javascript">
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<h2 id="the--operator"><a class="header" href="#the--operator">The ? operator</a></h2>
|
|
<p>There is an even shorter way to deal with <code>Result</code> (and <code>Option</code>), shorter than <code>match</code> and even shorter than <code>if let</code>. It is called the "question mark operator", and is just <code>?</code>. After a function that returns a result, you can add <code>?</code>. This will:</p>
|
|
<ul>
|
|
<li>return what is inside the <code>Result</code> if it is <code>Ok</code></li>
|
|
<li>pass the error back if it is <code>Err</code></li>
|
|
</ul>
|
|
<p>In other words, it does almost everything for you.</p>
|
|
<p>We can try this with <code>.parse()</code> again. We will write a function called <code>parse_str</code> that tries to turn a <code>&str</code> into a <code>i32</code>. It looks like this:</p>
|
|
<pre><pre class="playground"><code class="language-rust">use std::num::ParseIntError;
|
|
|
|
fn parse_str(input: &str) -> Result<i32, ParseIntError> {
|
|
let parsed_number = input.parse::<i32>()?; // Here is the question mark
|
|
Ok(parsed_number)
|
|
}
|
|
|
|
fn main() {}
|
|
</code></pre></pre>
|
|
<p>This function takes a <code>&str</code>. If it is <code>Ok</code>, it gives an <code>i32</code> wrapped in <code>Ok</code>. If it is an <code>Err</code>, it returns a <code>ParseIntError</code>. Then we try to parse the number, and add <code>?</code>. That means "check if it is an error, and give what is inside the Result if it is okay". If it is not okay, it will return the error and end. But if it is okay, it will go to the next line. On the next line is the number inside of <code>Ok()</code>. We need to wrap it in <code>Ok</code> because the return is <code>Result<i32, ParseIntError></code>, not <code>i32</code>.</p>
|
|
<p>Now, we can try out our function. Let's see what it does with a vec of <code>&str</code>s.</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn parse_str(input: &str) -> Result<i32, std::num::ParseIntError> {
|
|
let parsed_number = input.parse::<i32>()?;
|
|
Ok(parsed_number)
|
|
}
|
|
|
|
fn main() {
|
|
let str_vec = vec!["Seven", "8", "9.0", "nice", "6060"];
|
|
for item in str_vec {
|
|
let parsed = parse_str(item);
|
|
println!("{:?}", parsed);
|
|
}
|
|
}
|
|
</code></pre></pre>
|
|
<p>This prints:</p>
|
|
<pre><code class="language-text">Err(ParseIntError { kind: InvalidDigit })
|
|
Ok(8)
|
|
Err(ParseIntError { kind: InvalidDigit })
|
|
Err(ParseIntError { kind: InvalidDigit })
|
|
Ok(6060)
|
|
</code></pre>
|
|
<p>How did we find <code>std::num::ParseIntError</code>? One easy way is to "ask" the compiler again.</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
let failure = "Not a number".parse::<i32>();
|
|
failure.rbrbrb(); // ⚠️ Compiler: "What is rbrbrb()???"
|
|
}
|
|
</code></pre></pre>
|
|
<p>The compiler doesn't understand, and says:</p>
|
|
<pre><code class="language-text">error[E0599]: no method named `rbrbrb` found for enum `std::result::Result<i32, std::num::ParseIntError>` in the current scope
|
|
--> src\main.rs:3:13
|
|
|
|
|
3 | failure.rbrbrb();
|
|
| ^^^^^^ method not found in `std::result::Result<i32, std::num::ParseIntError>`
|
|
</code></pre>
|
|
<p>So <code>std::result::Result<i32, std::num::ParseIntError></code> is the signature we need.</p>
|
|
<p>We don't need to write <code>std::result::Result</code> because <code>Result</code> is always "in scope" (in scope = ready to use). Rust does this for all the types we use a lot so we don't have to write <code>std::result::Result</code>, <code>std::collections::Vec</code>, etc.</p>
|
|
<p>We aren't working with things like files yet, so the ? operator doesn't look too useful yet. But here is a useless but quick example that shows how you can use it on a single line. Instead of making an <code>i32</code> with <code>.parse()</code>, we'll do a lot more. We'll make an <code>u16</code>, then turn it to a <code>String</code>, then a <code>u32</code>, then to a <code>String</code> again, and finally to a <code>i32</code>.</p>
|
|
<pre><pre class="playground"><code class="language-rust">use std::num::ParseIntError;
|
|
|
|
fn parse_str(input: &str) -> Result<i32, ParseIntError> {
|
|
let parsed_number = input.parse::<u16>()?.to_string().parse::<u32>()?.to_string().parse::<i32>()?; // Add a ? each time to check and pass it on
|
|
Ok(parsed_number)
|
|
}
|
|
|
|
fn main() {
|
|
let str_vec = vec!["Seven", "8", "9.0", "nice", "6060"];
|
|
for item in str_vec {
|
|
let parsed = parse_str(item);
|
|
println!("{:?}", parsed);
|
|
}
|
|
}
|
|
</code></pre></pre>
|
|
<p>This prints the same thing, but this time we handled three <code>Result</code>s in a single line. Later on we will do this with files, because they always return <code>Result</code>s because many things can go wrong.</p>
|
|
<p>Imagine the following: you want to open a file, write to it, and close it. First you need to successfully find the file (that's a <code>Result</code>). Then you need to successfully write to it (that's a <code>Result</code>). With <code>?</code> you can do that on one line.</p>
|
|
<h3 id="when-panic-and-unwrap-are-good"><a class="header" href="#when-panic-and-unwrap-are-good">When panic and unwrap are good</a></h3>
|
|
<p>Rust has a <code>panic!</code> macro that you can use to make it panic. It is easy to use:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
panic!("Time to panic!");
|
|
}
|
|
</code></pre></pre>
|
|
<p>The message <code>"Time to panic!"</code> displays when you run the program: <code>thread 'main' panicked at 'Time to panic!', src\main.rs:2:3</code></p>
|
|
<p>You will remember that <code>src\main.rs</code> is the directory and file name, and <code>2:3</code> is the line and column name. With this information, you can find the code and fix it.</p>
|
|
<p><code>panic!</code> is a good macro to use to make sure that you know when something changes. For example, this function called <code>prints_three_things</code> always prints index [0], [1], and [2] from a vector. It is okay because we always give it a vector with three items:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn prints_three_things(vector: Vec<i32>) {
|
|
println!("{}, {}, {}", vector[0], vector[1], vector[2]);
|
|
}
|
|
|
|
fn main() {
|
|
let my_vec = vec![8, 9, 10];
|
|
prints_three_things(my_vec);
|
|
}
|
|
</code></pre></pre>
|
|
<p>It prints <code>8, 9, 10</code> and everything is fine.</p>
|
|
<p>But imagine that later on we write more and more code, and forget that <code>my_vec</code> can only be three things. Now <code>my_vec</code> in this part has six things:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn prints_three_things(vector: Vec<i32>) {
|
|
println!("{}, {}, {}", vector[0], vector[1], vector[2]);
|
|
}
|
|
|
|
fn main() {
|
|
let my_vec = vec![8, 9, 10, 10, 55, 99]; // Now my_vec has six things
|
|
prints_three_things(my_vec);
|
|
}
|
|
</code></pre></pre>
|
|
<p>No error happens, because [0] and [1] and [2] are all inside this longer <code>Vec</code>. But what if it was really important to only have three things? We wouldn't know that there was a problem because the program doesn't panic. We should have done this instead:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn prints_three_things(vector: Vec<i32>) {
|
|
if vector.len() != 3 {
|
|
panic!("my_vec must always have three items") // will panic if the length is not 3
|
|
}
|
|
println!("{}, {}, {}", vector[0], vector[1], vector[2]);
|
|
}
|
|
|
|
fn main() {
|
|
let my_vec = vec![8, 9, 10];
|
|
prints_three_things(my_vec);
|
|
}
|
|
</code></pre></pre>
|
|
<p>Now we will know if the vector has six items because it panics as it should:</p>
|
|
<pre><pre class="playground"><code class="language-rust"> // ⚠️
|
|
fn prints_three_things(vector: Vec<i32>) {
|
|
if vector.len() != 3 {
|
|
panic!("my_vec must always have three items")
|
|
}
|
|
println!("{}, {}, {}", vector[0], vector[1], vector[2]);
|
|
}
|
|
|
|
fn main() {
|
|
let my_vec = vec![8, 9, 10, 10, 55, 99];
|
|
prints_three_things(my_vec);
|
|
}
|
|
</code></pre></pre>
|
|
<p>This gives us <code>thread 'main' panicked at 'my_vec must always have three items', src\main.rs:8:9</code>. Thanks to <code>panic!</code>, we now remember that <code>my_vec</code> should only have three items. So <code>panic!</code> is a good macro to create reminders in your code.</p>
|
|
<p>There are three other macros that are similar to <code>panic!</code> that you use a lot in testing. They are: <code>assert!</code>, <code>assert_eq!</code>, and <code>assert_ne!</code>.</p>
|
|
<p>Here is what they mean:</p>
|
|
<ul>
|
|
<li><code>assert!()</code>: if the part inside <code>()</code> is not true, the program will panic.</li>
|
|
<li><code>assert_eq!()</code>: the two items inside <code>()</code> must be equal.</li>
|
|
<li><code>assert_ne!()</code>: the two items inside <code>()</code> must not be equal. (<em>ne</em> means not equal)</li>
|
|
</ul>
|
|
<p>Some examples:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
let my_name = "Loki Laufeyson";
|
|
|
|
assert!(my_name == "Loki Laufeyson");
|
|
assert_eq!(my_name, "Loki Laufeyson");
|
|
assert_ne!(my_name, "Mithridates");
|
|
}
|
|
</code></pre></pre>
|
|
<p>This will do nothing, because all three assert macros are okay. (This is what we want)</p>
|
|
<p>You can also add a message if you want.</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
let my_name = "Loki Laufeyson";
|
|
|
|
assert!(
|
|
my_name == "Loki Laufeyson",
|
|
"{} should be Loki Laufeyson",
|
|
my_name
|
|
);
|
|
assert_eq!(
|
|
my_name, "Loki Laufeyson",
|
|
"{} and Loki Laufeyson should be equal",
|
|
my_name
|
|
);
|
|
assert_ne!(
|
|
my_name, "Mithridates",
|
|
"You entered {}. Input must not equal Mithridates",
|
|
my_name
|
|
);
|
|
}
|
|
</code></pre></pre>
|
|
<p>These messages will only display if the program panics. So if you run this:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
let my_name = "Mithridates";
|
|
|
|
assert_ne!(
|
|
my_name, "Mithridates",
|
|
"You enter {}. Input must not equal Mithridates",
|
|
my_name
|
|
);
|
|
}
|
|
</code></pre></pre>
|
|
<p>It will display:</p>
|
|
<pre><code class="language-text">thread 'main' panicked at 'assertion failed: `(left != right)`
|
|
left: `"Mithridates"`,
|
|
right: `"Mithridates"`: You entered Mithridates. Input must not equal Mithridates', src\main.rs:4:5
|
|
</code></pre>
|
|
<p>So it is saying "you said that left != right, but left == right". And it displays our message that says <code>You entered Mithridates. Input must not equal Mithridates</code>.</p>
|
|
<p><code>unwrap</code> is also good when you are writing your program and you want it to crash when there is a problem. Later, when your code is finished it is good to change <code>unwrap</code> to something else that won't crash.</p>
|
|
<p>You can also use <code>expect</code>, which is like <code>unwrap</code> but a bit better because you give it your own message. Textbooks usually give this advice: "If you use <code>.unwrap()</code> a lot, at least use <code>.expect()</code> for better error messages."</p>
|
|
<p>This will crash:</p>
|
|
<pre><pre class="playground"><code class="language-rust"> // ⚠️
|
|
fn get_fourth(input: &Vec<i32>) -> i32 {
|
|
let fourth = input.get(3).unwrap();
|
|
*fourth
|
|
}
|
|
|
|
fn main() {
|
|
let my_vec = vec![9, 0, 10];
|
|
let fourth = get_fourth(&my_vec);
|
|
}
|
|
</code></pre></pre>
|
|
<p>The error message is <code>thread 'main' panicked at 'called Option::unwrap() on a None value', src\main.rs:7:18</code>.</p>
|
|
<p>Now we write our own message with <code>expect</code>:</p>
|
|
<pre><pre class="playground"><code class="language-rust"> // ⚠️
|
|
fn get_fourth(input: &Vec<i32>) -> i32 {
|
|
let fourth = input.get(3).expect("Input vector needs at least 4 items");
|
|
*fourth
|
|
}
|
|
|
|
fn main() {
|
|
let my_vec = vec![9, 0, 10];
|
|
let fourth = get_fourth(&my_vec);
|
|
}
|
|
</code></pre></pre>
|
|
<p>It crashes again, but the error is better: <code>thread 'main' panicked at 'Input vector needs at least 4 items', src\main.rs:7:18</code>. <code>.expect()</code> is a little better than <code>.unwrap()</code> because of this, but it will still panic on <code>None</code>. Now here is an example of a bad practice, a function that tries to unwrap two times. It takes a <code>Vec<Option<i32>></code>, so maybe each part will have a <code>Some<i32></code> or maybe a <code>None</code>.</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn try_two_unwraps(input: Vec<Option<i32>>) {
|
|
println!("Index 0 is: {}", input[0].unwrap());
|
|
println!("Index 1 is: {}", input[1].unwrap());
|
|
}
|
|
|
|
fn main() {
|
|
let vector = vec![None, Some(1000)]; // This vector has a None, so it will panic
|
|
try_two_unwraps(vector);
|
|
}
|
|
</code></pre></pre>
|
|
<p>The message is: <code>thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src\main.rs:2:32</code>. We're not sure if it was the first <code>.unwrap()</code> or the second <code>.unwrap()</code> until we check the line. It would be better to check the length and also to not unwrap. But with <code>.expect()</code> at least it will be a <em>little</em> better. Here it is with <code>.expect()</code>:</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn try_two_unwraps(input: Vec<Option<i32>>) {
|
|
println!("Index 0 is: {}", input[0].expect("The first unwrap had a None!"));
|
|
println!("Index 1 is: {}", input[1].expect("The second unwrap had a None!"));
|
|
}
|
|
|
|
fn main() {
|
|
let vector = vec![None, Some(1000)];
|
|
try_two_unwraps(vector);
|
|
}
|
|
</code></pre></pre>
|
|
<p>So that is a bit better: <code>thread 'main' panicked at 'The first unwrap had a None!', src\main.rs:2:32</code>. We have the line number as well so we can find it.</p>
|
|
<p>You can also use <code>unwrap_or</code> if you want to always have a value that you want to choose. If you do this it will never panic. That's:</p>
|
|
<ul>
|
|
<li>
|
|
<ol>
|
|
<li>good because your program won't panic, but</li>
|
|
</ol>
|
|
</li>
|
|
<li>
|
|
<ol start="2">
|
|
<li>maybe not good if you want the program to panic if there's a problem.</li>
|
|
</ol>
|
|
</li>
|
|
</ul>
|
|
<p>But usually we don't want our program to panic, so <code>unwrap_or</code> is a good method to use.</p>
|
|
<pre><pre class="playground"><code class="language-rust">fn main() {
|
|
let my_vec = vec![8, 9, 10];
|
|
|
|
let fourth = my_vec.get(3).unwrap_or(&0); // If .get doesn't work, we will make the value &0.
|
|
// .get returns a reference, so we need &0 and not 0
|
|
// You can write "let *fourth" with a * if you want fourth to be
|
|
// a 0 and not a &0, but here we just print so it doesn't matter
|
|
|
|
println!("{}", fourth);
|
|
}
|
|
</code></pre></pre>
|
|
<p>This prints <code>0</code> because <code>.unwrap_or(&0)</code> gives a 0 even if it is a <code>None</code>.</p>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
<a rel="prev" href="Chapter_32.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
<a rel="next" href="Chapter_34.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="Chapter_32.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
<a rel="next" href="Chapter_34.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
window.playground_copyable = true;
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|