1024 lines
71 KiB
HTML
1024 lines
71 KiB
HTML
|
<!DOCTYPE HTML>
|
|||
|
<html lang="en" class="sidebar-visible no-js light">
|
|||
|
<head>
|
|||
|
<!-- Book generated using mdBook -->
|
|||
|
<meta charset="UTF-8">
|
|||
|
<title>Programming a Guessing Game - The Rust Programming Language</title>
|
|||
|
|
|||
|
|
|||
|
<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="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 href="googleFonts/css.css" rel="stylesheet" type="text/css">
|
|||
|
|
|||
|
<!-- Highlight.js Stylesheets -->
|
|||
|
<link rel="stylesheet" href="highlight.css">
|
|||
|
<link rel="stylesheet" href="tomorrow-night.css">
|
|||
|
<link rel="stylesheet" href="ayu-highlight.css">
|
|||
|
|
|||
|
<!-- Custom theme stylesheets -->
|
|||
|
|
|||
|
<link rel="stylesheet" href="ferris.css">
|
|||
|
|
|||
|
<link rel="stylesheet" href="theme/2018-edition.css">
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<!-- Provide site root to javascript -->
|
|||
|
<script type="text/javascript">
|
|||
|
var path_to_root = "";
|
|||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "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 id="sidebar-scrollbox" class="sidebar-scrollbox">
|
|||
|
<ol class="chapter"><li class="expanded affix "><a href="title-page.html">The Rust Programming Language</a></li><li class="expanded affix "><a href="foreword.html">Foreword</a></li><li class="expanded affix "><a href="ch00-00-introduction.html">Introduction</a></li><li class="expanded "><a href="ch01-00-getting-started.html"><strong aria-hidden="true">1.</strong> Getting Started</a></li><li><ol class="section"><li class="expanded "><a href="ch01-01-installation.html"><strong aria-hidden="true">1.1.</strong> Installation</a></li><li class="expanded "><a href="ch01-02-hello-world.html"><strong aria-hidden="true">1.2.</strong> Hello, World!</a></li><li class="expanded "><a href="ch01-03-hello-cargo.html"><strong aria-hidden="true">1.3.</strong> Hello, Cargo!</a></li></ol></li><li class="expanded "><a href="ch02-00-guessing-game-tutorial.html" class="active"><strong aria-hidden="true">2.</strong> Programming a Guessing Game</a></li><li class="expanded "><a href="ch03-00-common-programming-concepts.html"><strong aria-hidden="true">3.</strong> Common Programming Concepts</a></li><li><ol class="section"><li class="expanded "><a href="ch03-01-variables-and-mutability.html"><strong aria-hidden="true">3.1.</strong> Variables and Mutability</a></li><li class="expanded "><a href="ch03-02-data-types.html"><strong aria-hidden="true">3.2.</strong> Data Types</a></li><li class="expanded "><a href="ch03-03-how-functions-work.html"><strong aria-hidden="true">3.3.</strong> Functions</a></li><li class="expanded "><a href="ch03-04-comments.html"><strong aria-hidden="true">3.4.</strong> Comments</a></li><li class="expanded "><a href="ch03-05-control-flow.html"><strong aria-hidden="true">3.5.</strong> Control Flow</a></li></ol></li><li class="expanded "><a href="ch04-00-understanding-ownership.html"><strong aria-hidden="true">4.</strong> Understanding Ownership</a></li><li><ol class="section"><li class="expanded "><a href="ch04-01-what-is-ownership.html"><strong aria-hidden="true">4.1.</strong> What is Ownership?</a></li><li class="expanded "><a href="ch04-02-references-and-borrowing.html"><strong aria-hidden="true">4.2.</strong> References and Borrowing</a></li><li class="expanded "><a href="ch04-03-slices.html"><strong aria-hidden="true">4.3.</strong> The Slice Type</a></li></ol></li><li class="expanded "><a href="ch05-00-structs.html"><strong aria-hidden="true">5.</strong> Using Structs to Structure Related Data</a></li><li><ol class="section"><li class="expanded "><a href="ch05-01-defining-structs.html"><strong aria-hidden="true">5.1.</strong> Defining and Instantiating Structs</a></li><li class="expanded "><a href="ch05-02-example-structs.html"><strong aria-hidden="true">5.2.</strong> An Example Program Using Structs</a></li><li class="expanded "><a href="ch05-03-method-syntax.html"><strong aria-hidden="true">5.3.</strong> Method Syntax</a></li></ol></li><li class="expanded "><a href="ch06-00-enums.html"><strong aria-hidden="true">6.</strong> Enums and Pattern Matching</a></li><li><ol class="section"><li class="expanded "><a href="ch06-01-defining-an-enum.html"><strong aria-hidden="true">6.1.</strong> Defining an Enum</a></li><li class="expanded "><a href="ch06-02-match.html"><strong aria-hidden="true">6.2.</strong> The match Control Flow Operator</a></li><li class="expanded "><a href="ch06-03-if-let.html"><strong aria-hidden="true">6.3.</strong> Concise Control Flow with if let</a></li></ol></li><li class="expanded "><a href="ch07-00-managing-growing-projects-with-packages-crates-and-modules.html"><strong aria-hidden="true">7.</strong> Managing Growing Projects with Packages, Crates, and Modules</a></li><li><ol class="section"><li class="expanded "><a href="ch07-01-packages-and-crates.html"><strong aria-hidden="true">7.1.</strong> Packages and Crates</a></li><li class="expanded "><a href="ch07-02-defining-modules-to-control-scope-and-privacy.html"><strong aria-hidden="true">7.2.</strong> Defining Modules to Control Scope and Privacy</a></li><li class="expanded "><a href="ch07-03-paths-for-referring-to-an-item-in-the-modu
|
|||
|
</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" class="menu-bar">
|
|||
|
<div id="menu-bar-sticky-container">
|
|||
|
<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">The Rust Programming Language</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>
|
|||
|
|
|||
|
|
|||
|
<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>
|
|||
|
<h1><a class="header" href="#programming-a-guessing-game" id="programming-a-guessing-game">Programming a Guessing Game</a></h1>
|
|||
|
<p>Let’s jump into Rust by working through a hands-on project together! This
|
|||
|
chapter introduces you to a few common Rust concepts by showing you how to use
|
|||
|
them in a real program. You’ll learn about <code>let</code>, <code>match</code>, methods, associated
|
|||
|
functions, using external crates, and more! The following chapters will explore
|
|||
|
these ideas in more detail. In this chapter, you’ll practice the fundamentals.</p>
|
|||
|
<p>We’ll implement a classic beginner programming problem: a guessing game. Here’s
|
|||
|
how it works: the program will generate a random integer between 1 and 100. It
|
|||
|
will then prompt the player to enter a guess. After a guess is entered, the
|
|||
|
program will indicate whether the guess is too low or too high. If the guess is
|
|||
|
correct, the game will print a congratulatory message and exit.</p>
|
|||
|
<h2><a class="header" href="#setting-up-a-new-project" id="setting-up-a-new-project">Setting Up a New Project</a></h2>
|
|||
|
<p>To set up a new project, go to the <em>projects</em> directory that you created in
|
|||
|
Chapter 1 and make a new project using Cargo, like so:</p>
|
|||
|
<pre><code class="language-text">$ cargo new guessing_game
|
|||
|
$ cd guessing_game
|
|||
|
</code></pre>
|
|||
|
<p>The first command, <code>cargo new</code>, takes the name of the project (<code>guessing_game</code>)
|
|||
|
as the first argument. The second command changes to the new project’s
|
|||
|
directory.</p>
|
|||
|
<p>Look at the generated <em>Cargo.toml</em> file:</p>
|
|||
|
<p><span class="filename">Filename: Cargo.toml</span></p>
|
|||
|
<pre><code class="language-toml">[package]
|
|||
|
name = "guessing_game"
|
|||
|
version = "0.1.0"
|
|||
|
authors = ["Your Name <you@example.com>"]
|
|||
|
edition = "2018"
|
|||
|
|
|||
|
[dependencies]
|
|||
|
</code></pre>
|
|||
|
<p>If the author information that Cargo obtained from your environment is not
|
|||
|
correct, fix that in the file and save it again.</p>
|
|||
|
<p>As you saw in Chapter 1, <code>cargo new</code> generates a “Hello, world!” program for
|
|||
|
you. Check out the <em>src/main.rs</em> file:</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><pre class="playpen"><code class="language-rust">fn main() {
|
|||
|
println!("Hello, world!");
|
|||
|
}
|
|||
|
</code></pre></pre>
|
|||
|
<p>Now let’s compile this “Hello, world!” program and run it in the same step
|
|||
|
using the <code>cargo run</code> command:</p>
|
|||
|
<pre><code class="language-text">$ cargo run
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 1.50 secs
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Hello, world!
|
|||
|
</code></pre>
|
|||
|
<p>The <code>run</code> command comes in handy when you need to rapidly iterate on a project,
|
|||
|
as we’ll do in this game, quickly testing each iteration before moving on to
|
|||
|
the next one.</p>
|
|||
|
<p>Reopen the <em>src/main.rs</em> file. You’ll be writing all the code in this file.</p>
|
|||
|
<h2><a class="header" href="#processing-a-guess" id="processing-a-guess">Processing a Guess</a></h2>
|
|||
|
<p>The first part of the guessing game program will ask for user input, process
|
|||
|
that input, and check that the input is in the expected form. To start, we’ll
|
|||
|
allow the player to input a guess. Enter the code in Listing 2-1 into
|
|||
|
<em>src/main.rs</em>.</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">use std::io;
|
|||
|
|
|||
|
fn main() {
|
|||
|
println!("Guess the number!");
|
|||
|
|
|||
|
println!("Please input your guess.");
|
|||
|
|
|||
|
let mut guess = String::new();
|
|||
|
|
|||
|
io::stdin().read_line(&mut guess)
|
|||
|
.expect("Failed to read line");
|
|||
|
|
|||
|
println!("You guessed: {}", guess);
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p><span class="caption">Listing 2-1: Code that gets a guess from the user and
|
|||
|
prints it</span></p>
|
|||
|
<p>This code contains a lot of information, so let’s go over it line by line. To
|
|||
|
obtain user input and then print the result as output, we need to bring the
|
|||
|
<code>io</code> (input/output) library into scope. The <code>io</code> library comes from the
|
|||
|
standard library (which is known as <code>std</code>):</p>
|
|||
|
<pre><code class="language-rust ignore">use std::io;
|
|||
|
</code></pre>
|
|||
|
<p>By default, Rust brings only a few types into the scope of every program in
|
|||
|
<a href="../std/prelude/index.html">the <em>prelude</em></a><!-- ignore -->. If a type you want to use isn’t in the
|
|||
|
prelude, you have to bring that type into scope explicitly with a <code>use</code>
|
|||
|
statement. Using the <code>std::io</code> library provides you with a number of useful
|
|||
|
features, including the ability to accept user input.</p>
|
|||
|
<p>As you saw in Chapter 1, the <code>main</code> function is the entry point into the
|
|||
|
program:</p>
|
|||
|
<pre><code class="language-rust ignore">fn main() {
|
|||
|
</code></pre>
|
|||
|
<p>The <code>fn</code> syntax declares a new function, the parentheses, <code>()</code>, indicate there
|
|||
|
are no parameters, and the curly bracket, <code>{</code>, starts the body of the function.</p>
|
|||
|
<p>As you also learned in Chapter 1, <code>println!</code> is a macro that prints a string to
|
|||
|
the screen:</p>
|
|||
|
<pre><code class="language-rust ignore">println!("Guess the number!");
|
|||
|
|
|||
|
println!("Please input your guess.");
|
|||
|
</code></pre>
|
|||
|
<p>This code is printing a prompt stating what the game is and requesting input
|
|||
|
from the user.</p>
|
|||
|
<h3><a class="header" href="#storing-values-with-variables" id="storing-values-with-variables">Storing Values with Variables</a></h3>
|
|||
|
<p>Next, we’ll create a place to store the user input, like this:</p>
|
|||
|
<pre><code class="language-rust ignore">let mut guess = String::new();
|
|||
|
</code></pre>
|
|||
|
<p>Now the program is getting interesting! There’s a lot going on in this little
|
|||
|
line. Notice that this is a <code>let</code> statement, which is used to create a
|
|||
|
<em>variable</em>. Here’s another example:</p>
|
|||
|
<pre><code class="language-rust ignore">let foo = bar;
|
|||
|
</code></pre>
|
|||
|
<p>This line creates a new variable named <code>foo</code> and binds it to the value of the
|
|||
|
<code>bar</code> variable. In Rust, variables are immutable by default. We’ll be
|
|||
|
discussing this concept in detail in the <a href="ch03-01-variables-and-mutability.html#variables-and-mutability">“Variables and
|
|||
|
Mutability”</a><!-- ignore --> section in Chapter 3.
|
|||
|
The following example shows how to use <code>mut</code> before the variable name to make
|
|||
|
a variable mutable:</p>
|
|||
|
<pre><code class="language-rust ignore">let foo = 5; // immutable
|
|||
|
let mut bar = 5; // mutable
|
|||
|
</code></pre>
|
|||
|
<blockquote>
|
|||
|
<p>Note: The <code>//</code> syntax starts a comment that continues until the end of the
|
|||
|
line. Rust ignores everything in comments, which are discussed in more detail
|
|||
|
in Chapter 3.</p>
|
|||
|
</blockquote>
|
|||
|
<p>Let’s return to the guessing game program. You now know that <code>let mut guess</code>
|
|||
|
will introduce a mutable variable named <code>guess</code>. On the other side of the equal
|
|||
|
sign (<code>=</code>) is the value that <code>guess</code> is bound to, which is the result of
|
|||
|
calling <code>String::new</code>, a function that returns a new instance of a <code>String</code>.
|
|||
|
<a href="../std/string/struct.String.html"><code>String</code></a><!-- ignore --> is a string type provided by the standard
|
|||
|
library that is a growable, UTF-8 encoded bit of text.</p>
|
|||
|
<p>The <code>::</code> syntax in the <code>::new</code> line indicates that <code>new</code> is an <em>associated
|
|||
|
function</em> of the <code>String</code> type. An associated function is implemented on a type,
|
|||
|
in this case <code>String</code>, rather than on a particular instance of a <code>String</code>. Some
|
|||
|
languages call this a <em>static method</em>.</p>
|
|||
|
<p>This <code>new</code> function creates a new, empty string. You’ll find a <code>new</code> function
|
|||
|
on many types, because it’s a common name for a function that makes a new value
|
|||
|
of some kind.</p>
|
|||
|
<p>To summarize, the <code>let mut guess = String::new();</code> line has created a mutable
|
|||
|
variable that is currently bound to a new, empty instance of a <code>String</code>. Whew!</p>
|
|||
|
<p>Recall that we included the input/output functionality from the standard
|
|||
|
library with <code>use std::io;</code> on the first line of the program. Now we’ll call
|
|||
|
the <code>stdin</code> function from the <code>io</code> module:</p>
|
|||
|
<pre><code class="language-rust ignore">io::stdin().read_line(&mut guess)
|
|||
|
.expect("Failed to read line");
|
|||
|
</code></pre>
|
|||
|
<p>If we hadn’t put the <code>use std::io</code> line at the beginning of the program, we
|
|||
|
could have written this function call as <code>std::io::stdin</code>. The <code>stdin</code> function
|
|||
|
returns an instance of <a href="../std/io/struct.Stdin.html"><code>std::io::Stdin</code></a><!-- ignore -->, which is a
|
|||
|
type that represents a handle to the standard input for your terminal.</p>
|
|||
|
<p>The next part of the code, <code>.read_line(&mut guess)</code>, calls the
|
|||
|
<a href="../std/io/struct.Stdin.html#method.read_line"><code>read_line</code></a><!-- ignore --> method on the standard input handle to
|
|||
|
get input from the user. We’re also passing one argument to <code>read_line</code>: <code>&mut guess</code>.</p>
|
|||
|
<p>The job of <code>read_line</code> is to take whatever the user types into standard input
|
|||
|
and place that into a string, so it takes that string as an argument. The
|
|||
|
string argument needs to be mutable so the method can change the string’s
|
|||
|
content by adding the user input.</p>
|
|||
|
<p>The <code>&</code> indicates that this argument is a <em>reference</em>, which gives you a way to
|
|||
|
let multiple parts of your code access one piece of data without needing to
|
|||
|
copy that data into memory multiple times. References are a complex feature,
|
|||
|
and one of Rust’s major advantages is how safe and easy it is to use
|
|||
|
references. You don’t need to know a lot of those details to finish this
|
|||
|
program. For now, all you need to know is that like variables, references are
|
|||
|
immutable by default. Hence, you need to write <code>&mut guess</code> rather than
|
|||
|
<code>&guess</code> to make it mutable. (Chapter 4 will explain references more
|
|||
|
thoroughly.)</p>
|
|||
|
<h3><a class="header" href="#handling-potential-failure-with-the-result-type" id="handling-potential-failure-with-the-result-type">Handling Potential Failure with the <code>Result</code> Type</a></h3>
|
|||
|
<p>We’re not quite done with this line of code. Although what we’ve discussed so
|
|||
|
far is a single line of text, it’s only the first part of the single logical
|
|||
|
line of code. The second part is this method:</p>
|
|||
|
<pre><code class="language-rust ignore">.expect("Failed to read line");
|
|||
|
</code></pre>
|
|||
|
<p>When you call a method with the <code>.foo()</code> syntax, it’s often wise to introduce a
|
|||
|
newline and other whitespace to help break up long lines. We could have
|
|||
|
written this code as:</p>
|
|||
|
<pre><code class="language-rust ignore">io::stdin().read_line(&mut guess).expect("Failed to read line");
|
|||
|
</code></pre>
|
|||
|
<p>However, one long line is difficult to read, so it’s best to divide it: two
|
|||
|
lines for two method calls. Now let’s discuss what this line does.</p>
|
|||
|
<p>As mentioned earlier, <code>read_line</code> puts what the user types into the string
|
|||
|
we’re passing it, but it also returns a value—in this case, an
|
|||
|
<a href="../std/io/type.Result.html"><code>io::Result</code></a><!-- ignore -->. Rust has a number of types named
|
|||
|
<code>Result</code> in its standard library: a generic <a href="../std/result/enum.Result.html"><code>Result</code></a><!-- ignore -->
|
|||
|
as well as specific versions for submodules, such as <code>io::Result</code>.</p>
|
|||
|
<p>The <code>Result</code> types are <a href="ch06-00-enums.html"><em>enumerations</em></a><!-- ignore -->, often referred
|
|||
|
to as <em>enums</em>. An enumeration is a type that can have a fixed set of values,
|
|||
|
and those values are called the enum’s <em>variants</em>. Chapter 6 will cover enums
|
|||
|
in more detail.</p>
|
|||
|
<p>For <code>Result</code>, the variants are <code>Ok</code> or <code>Err</code>. The <code>Ok</code> variant indicates the
|
|||
|
operation was successful, and inside <code>Ok</code> is the successfully generated value.
|
|||
|
The <code>Err</code> variant means the operation failed, and <code>Err</code> contains information
|
|||
|
about how or why the operation failed.</p>
|
|||
|
<p>The purpose of these <code>Result</code> types is to encode error-handling information.
|
|||
|
Values of the <code>Result</code> type, like values of any type, have methods defined on
|
|||
|
them. An instance of <code>io::Result</code> has an <a href="../std/result/enum.Result.html#method.expect"><code>expect</code> method</a><!-- ignore
|
|||
|
--> that you can call. If this instance of <code>io::Result</code> is an <code>Err</code> value,
|
|||
|
<code>expect</code> will cause the program to crash and display the message that you
|
|||
|
passed as an argument to <code>expect</code>. If the <code>read_line</code> method returns an <code>Err</code>,
|
|||
|
it would likely be the result of an error coming from the underlying operating
|
|||
|
system. If this instance of <code>io::Result</code> is an <code>Ok</code> value, <code>expect</code> will take
|
|||
|
the return value that <code>Ok</code> is holding and return just that value to you so you
|
|||
|
can use it. In this case, that value is the number of bytes in what the user
|
|||
|
entered into standard input.</p>
|
|||
|
<p>If you don’t call <code>expect</code>, the program will compile, but you’ll get a warning:</p>
|
|||
|
<pre><code class="language-text">$ cargo build
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
warning: unused `std::result::Result` which must be used
|
|||
|
--> src/main.rs:10:5
|
|||
|
|
|
|||
|
10 | io::stdin().read_line(&mut guess);
|
|||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|||
|
|
|
|||
|
= note: #[warn(unused_must_use)] on by default
|
|||
|
</code></pre>
|
|||
|
<p>Rust warns that you haven’t used the <code>Result</code> value returned from <code>read_line</code>,
|
|||
|
indicating that the program hasn’t handled a possible error.</p>
|
|||
|
<p>The right way to suppress the warning is to actually write error handling, but
|
|||
|
because you just want to crash this program when a problem occurs, you can use
|
|||
|
<code>expect</code>. You’ll learn about recovering from errors in Chapter 9.</p>
|
|||
|
<h3><a class="header" href="#printing-values-with-println-placeholders" id="printing-values-with-println-placeholders">Printing Values with <code>println!</code> Placeholders</a></h3>
|
|||
|
<p>Aside from the closing curly brackets, there’s only one more line to discuss in
|
|||
|
the code added so far, which is the following:</p>
|
|||
|
<pre><code class="language-rust ignore">println!("You guessed: {}", guess);
|
|||
|
</code></pre>
|
|||
|
<p>This line prints the string we saved the user’s input in. The set of curly
|
|||
|
brackets, <code>{}</code>, is a placeholder: think of <code>{}</code> as little crab pincers that
|
|||
|
hold a value in place. You can print more than one value using curly brackets:
|
|||
|
the first set of curly brackets holds the first value listed after the format
|
|||
|
string, the second set holds the second value, and so on. Printing multiple
|
|||
|
values in one call to <code>println!</code> would look like this:</p>
|
|||
|
<pre><pre class="playpen"><code class="language-rust">
|
|||
|
<span class="boring">#![allow(unused_variables)]
|
|||
|
</span><span class="boring">fn main() {
|
|||
|
</span>let x = 5;
|
|||
|
let y = 10;
|
|||
|
|
|||
|
println!("x = {} and y = {}", x, y);
|
|||
|
<span class="boring">}
|
|||
|
</span></code></pre></pre>
|
|||
|
<p>This code would print <code>x = 5 and y = 10</code>.</p>
|
|||
|
<h3><a class="header" href="#testing-the-first-part" id="testing-the-first-part">Testing the First Part</a></h3>
|
|||
|
<p>Let’s test the first part of the guessing game. Run it using <code>cargo run</code>:</p>
|
|||
|
<pre><code class="language-text">$ cargo run
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 2.53 secs
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Guess the number!
|
|||
|
Please input your guess.
|
|||
|
6
|
|||
|
You guessed: 6
|
|||
|
</code></pre>
|
|||
|
<p>At this point, the first part of the game is done: we’re getting input from the
|
|||
|
keyboard and then printing it.</p>
|
|||
|
<h2><a class="header" href="#generating-a-secret-number" id="generating-a-secret-number">Generating a Secret Number</a></h2>
|
|||
|
<p>Next, we need to generate a secret number that the user will try to guess. The
|
|||
|
secret number should be different every time so the game is fun to play more
|
|||
|
than once. Let’s use a random number between 1 and 100 so the game isn’t too
|
|||
|
difficult. Rust doesn’t yet include random number functionality in its standard
|
|||
|
library. However, the Rust team does provide a <a href="https://crates.io/crates/rand"><code>rand</code> crate</a>.</p>
|
|||
|
<h3><a class="header" href="#using-a-crate-to-get-more-functionality" id="using-a-crate-to-get-more-functionality">Using a Crate to Get More Functionality</a></h3>
|
|||
|
<p>Remember that a crate is a collection of Rust source code files.
|
|||
|
The project we’ve been building is a <em>binary crate</em>, which is an executable.
|
|||
|
The <code>rand</code> crate is a <em>library crate</em>, which contains code intended to be
|
|||
|
used in other programs.</p>
|
|||
|
<p>Cargo’s use of external crates is where it really shines. Before we can write
|
|||
|
code that uses <code>rand</code>, we need to modify the <em>Cargo.toml</em> file to include the
|
|||
|
<code>rand</code> crate as a dependency. Open that file now and add the following line to
|
|||
|
the bottom beneath the <code>[dependencies]</code> section header that Cargo created for
|
|||
|
you:</p>
|
|||
|
<!-- When updating the version of `rand` used, also update the version of
|
|||
|
`rand` used in these files so they all match:
|
|||
|
* ch07-04-bringing-paths-into-scope-with-the-use-keyword.md
|
|||
|
* ch14-03-cargo-workspaces.md
|
|||
|
-->
|
|||
|
<p><span class="filename">Filename: Cargo.toml</span></p>
|
|||
|
<pre><code class="language-toml">[dependencies]
|
|||
|
rand = "0.5.5"
|
|||
|
</code></pre>
|
|||
|
<p>In the <em>Cargo.toml</em> file, everything that follows a header is part of a section
|
|||
|
that continues until another section starts. The <code>[dependencies]</code> section is
|
|||
|
where you tell Cargo which external crates your project depends on and which
|
|||
|
versions of those crates you require. In this case, we’ll specify the <code>rand</code>
|
|||
|
crate with the semantic version specifier <code>0.5.5</code>. Cargo understands <a href="http://semver.org">Semantic
|
|||
|
Versioning</a><!-- ignore --> (sometimes called <em>SemVer</em>), which is a
|
|||
|
standard for writing version numbers. The number <code>0.5.5</code> is actually shorthand
|
|||
|
for <code>^0.5.5</code>, which means “any version that has a public API compatible with
|
|||
|
version 0.5.5.”</p>
|
|||
|
<p>Now, without changing any of the code, let’s build the project, as shown in
|
|||
|
Listing 2-2.</p>
|
|||
|
<pre><code class="language-text">$ cargo build
|
|||
|
Updating crates.io index
|
|||
|
Downloaded rand v0.5.5
|
|||
|
Downloaded libc v0.2.62
|
|||
|
Downloaded rand_core v0.2.2
|
|||
|
Downloaded rand_core v0.3.1
|
|||
|
Downloaded rand_core v0.4.2
|
|||
|
Compiling rand_core v0.4.2
|
|||
|
Compiling libc v0.2.62
|
|||
|
Compiling rand_core v0.3.1
|
|||
|
Compiling rand_core v0.2.2
|
|||
|
Compiling rand v0.5.5
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 2.53 s
|
|||
|
</code></pre>
|
|||
|
<p><span class="caption">Listing 2-2: The output from running <code>cargo build</code> after
|
|||
|
adding the rand crate as a dependency</span></p>
|
|||
|
<p>You may see different version numbers (but they will all be compatible with
|
|||
|
the code, thanks to SemVer!), and the lines may be in a different order.</p>
|
|||
|
<p>Now that we have an external dependency, Cargo fetches the latest versions of
|
|||
|
everything from the <em>registry</em>, which is a copy of data from
|
|||
|
<a href="https://crates.io/">Crates.io</a>. Crates.io is where people in the Rust ecosystem post
|
|||
|
their open source Rust projects for others to use.</p>
|
|||
|
<p>After updating the registry, Cargo checks the <code>[dependencies]</code> section and
|
|||
|
downloads any crates you don’t have yet. In this case, although we only listed
|
|||
|
<code>rand</code> as a dependency, Cargo also grabbed <code>libc</code> and <code>rand_core</code>, because <code>rand</code>
|
|||
|
depends on those to work. After downloading the crates, Rust compiles them and
|
|||
|
then compiles the project with the dependencies available.</p>
|
|||
|
<p>If you immediately run <code>cargo build</code> again without making any changes, you
|
|||
|
won’t get any output aside from the <code>Finished</code> line. Cargo knows it has already
|
|||
|
downloaded and compiled the dependencies, and you haven’t changed anything
|
|||
|
about them in your <em>Cargo.toml</em> file. Cargo also knows that you haven’t changed
|
|||
|
anything about your code, so it doesn’t recompile that either. With nothing to
|
|||
|
do, it simply exits.</p>
|
|||
|
<p>If you open up the <em>src/main.rs</em> file, make a trivial change, and then save it
|
|||
|
and build again, you’ll only see two lines of output:</p>
|
|||
|
<pre><code class="language-text">$ cargo build
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 2.53s
|
|||
|
</code></pre>
|
|||
|
<p>These lines show Cargo only updates the build with your tiny change to the
|
|||
|
<em>src/main.rs</em> file. Your dependencies haven’t changed, so Cargo knows it can
|
|||
|
reuse what it has already downloaded and compiled for those. It just rebuilds
|
|||
|
your part of the code.</p>
|
|||
|
<h4><a class="header" href="#ensuring-reproducible-builds-with-the-cargolock-file" id="ensuring-reproducible-builds-with-the-cargolock-file">Ensuring Reproducible Builds with the <em>Cargo.lock</em> File</a></h4>
|
|||
|
<p>Cargo has a mechanism that ensures you can rebuild the same artifact every time
|
|||
|
you or anyone else builds your code: Cargo will use only the versions of the
|
|||
|
dependencies you specified until you indicate otherwise. For example, what
|
|||
|
happens if next week version 0.5.6 of the <code>rand</code> crate comes out and
|
|||
|
contains an important bug fix but also contains a regression that will break
|
|||
|
your code?</p>
|
|||
|
<p>The answer to this problem is the <em>Cargo.lock</em> file, which was created the
|
|||
|
first time you ran <code>cargo build</code> and is now in your <em>guessing_game</em> directory.
|
|||
|
When you build a project for the first time, Cargo figures out all the
|
|||
|
versions of the dependencies that fit the criteria and then writes them to
|
|||
|
the <em>Cargo.lock</em> file. When you build your project in the future, Cargo will
|
|||
|
see that the <em>Cargo.lock</em> file exists and use the versions specified there
|
|||
|
rather than doing all the work of figuring out versions again. This lets you
|
|||
|
have a reproducible build automatically. In other words, your project will
|
|||
|
remain at <code>0.5.5</code> until you explicitly upgrade, thanks to the <em>Cargo.lock</em>
|
|||
|
file.</p>
|
|||
|
<h4><a class="header" href="#updating-a-crate-to-get-a-new-version" id="updating-a-crate-to-get-a-new-version">Updating a Crate to Get a New Version</a></h4>
|
|||
|
<p>When you <em>do</em> want to update a crate, Cargo provides another command, <code>update</code>,
|
|||
|
which will ignore the <em>Cargo.lock</em> file and figure out all the latest versions
|
|||
|
that fit your specifications in <em>Cargo.toml</em>. If that works, Cargo will write
|
|||
|
those versions to the <em>Cargo.lock</em> file.</p>
|
|||
|
<p>But by default, Cargo will only look for versions greater than <code>0.5.5</code> and less
|
|||
|
than <code>0.6.0</code>. If the <code>rand</code> crate has released two new versions, <code>0.5.6</code> and
|
|||
|
<code>0.6.0</code>, you would see the following if you ran <code>cargo update</code>:</p>
|
|||
|
<pre><code class="language-text">$ cargo update
|
|||
|
Updating crates.io index
|
|||
|
Updating rand v0.5.5 -> v0.5.6
|
|||
|
</code></pre>
|
|||
|
<p>At this point, you would also notice a change in your <em>Cargo.lock</em> file noting
|
|||
|
that the version of the <code>rand</code> crate you are now using is <code>0.5.6</code>.</p>
|
|||
|
<p>If you wanted to use <code>rand</code> version <code>0.6.0</code> or any version in the <code>0.6.x</code>
|
|||
|
series, you’d have to update the <em>Cargo.toml</em> file to look like this instead:</p>
|
|||
|
<pre><code class="language-toml">[dependencies]
|
|||
|
rand = "0.6.0"
|
|||
|
</code></pre>
|
|||
|
<p>The next time you run <code>cargo build</code>, Cargo will update the registry of crates
|
|||
|
available and reevaluate your <code>rand</code> requirements according to the new version
|
|||
|
you have specified.</p>
|
|||
|
<p>There’s a lot more to say about <a href="http://doc.crates.io">Cargo</a><!-- ignore --> and <a href="http://doc.crates.io/crates-io.html">its
|
|||
|
ecosystem</a><!-- ignore --> which we’ll discuss in Chapter 14, but
|
|||
|
for now, that’s all you need to know. Cargo makes it very easy to reuse
|
|||
|
libraries, so Rustaceans are able to write smaller projects that are assembled
|
|||
|
from a number of packages.</p>
|
|||
|
<h3><a class="header" href="#generating-a-random-number" id="generating-a-random-number">Generating a Random Number</a></h3>
|
|||
|
<p>Now that you’ve added the <code>rand</code> crate to <em>Cargo.toml</em>, let’s start using
|
|||
|
<code>rand</code>. The next step is to update <em>src/main.rs</em>, as shown in Listing 2-3.</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">use std::io;
|
|||
|
use rand::Rng;
|
|||
|
|
|||
|
fn main() {
|
|||
|
println!("Guess the number!");
|
|||
|
|
|||
|
let secret_number = rand::thread_rng().gen_range(1, 101);
|
|||
|
|
|||
|
println!("The secret number is: {}", secret_number);
|
|||
|
|
|||
|
println!("Please input your guess.");
|
|||
|
|
|||
|
let mut guess = String::new();
|
|||
|
|
|||
|
io::stdin().read_line(&mut guess)
|
|||
|
.expect("Failed to read line");
|
|||
|
|
|||
|
println!("You guessed: {}", guess);
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p><span class="caption">Listing 2-3: Adding code to generate a random
|
|||
|
number</span></p>
|
|||
|
<p>First, we add a <code>use</code> line: <code>use rand::Rng</code>. The <code>Rng</code> trait defines
|
|||
|
methods that random number generators implement, and this trait must be in
|
|||
|
scope for us to use those methods. Chapter 10 will cover traits in detail.</p>
|
|||
|
<p>Next, we’re adding two lines in the middle. The <code>rand::thread_rng</code> function
|
|||
|
will give us the particular random number generator that we’re going to use:
|
|||
|
one that is local to the current thread of execution and seeded by the
|
|||
|
operating system. Then we call the <code>gen_range</code> method on the random number
|
|||
|
generator. This method is defined by the <code>Rng</code> trait that we brought into
|
|||
|
scope with the <code>use rand::Rng</code> statement. The <code>gen_range</code> method takes two
|
|||
|
numbers as arguments and generates a random number between them. It’s inclusive
|
|||
|
on the lower bound but exclusive on the upper bound, so we need to specify <code>1</code>
|
|||
|
and <code>101</code> to request a number between 1 and 100.</p>
|
|||
|
<blockquote>
|
|||
|
<p>Note: You won’t just know which traits to use and which methods and functions
|
|||
|
to call from a crate. Instructions for using a crate are in each crate’s
|
|||
|
documentation. Another neat feature of Cargo is that you can run the <code>cargo doc --open</code> command, which will build documentation provided by all of your
|
|||
|
dependencies locally and open it in your browser. If you’re interested in
|
|||
|
other functionality in the <code>rand</code> crate, for example, run <code>cargo doc --open</code>
|
|||
|
and click <code>rand</code> in the sidebar on the left.</p>
|
|||
|
</blockquote>
|
|||
|
<p>The second line that we added to the middle of the code prints the secret
|
|||
|
number. This is useful while we’re developing the program to be able to test
|
|||
|
it, but we’ll delete it from the final version. It’s not much of a game if the
|
|||
|
program prints the answer as soon as it starts!</p>
|
|||
|
<p>Try running the program a few times:</p>
|
|||
|
<pre><code class="language-text">$ cargo run
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 2.53 secs
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Guess the number!
|
|||
|
The secret number is: 7
|
|||
|
Please input your guess.
|
|||
|
4
|
|||
|
You guessed: 4
|
|||
|
$ cargo run
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Guess the number!
|
|||
|
The secret number is: 83
|
|||
|
Please input your guess.
|
|||
|
5
|
|||
|
You guessed: 5
|
|||
|
</code></pre>
|
|||
|
<p>You should get different random numbers, and they should all be numbers between
|
|||
|
1 and 100. Great job!</p>
|
|||
|
<h2><a class="header" href="#comparing-the-guess-to-the-secret-number" id="comparing-the-guess-to-the-secret-number">Comparing the Guess to the Secret Number</a></h2>
|
|||
|
<p>Now that we have user input and a random number, we can compare them. That step
|
|||
|
is shown in Listing 2-4. Note that this code won’t compile quite yet, as we
|
|||
|
will explain.</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore does_not_compile">use std::io;
|
|||
|
use std::cmp::Ordering;
|
|||
|
use rand::Rng;
|
|||
|
|
|||
|
fn main() {
|
|||
|
|
|||
|
// ---snip---
|
|||
|
|
|||
|
println!("You guessed: {}", guess);
|
|||
|
|
|||
|
match guess.cmp(&secret_number) {
|
|||
|
Ordering::Less => println!("Too small!"),
|
|||
|
Ordering::Greater => println!("Too big!"),
|
|||
|
Ordering::Equal => println!("You win!"),
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p><span class="caption">Listing 2-4: Handling the possible return values of
|
|||
|
comparing two numbers</span></p>
|
|||
|
<p>The first new bit here is another <code>use</code> statement, bringing a type called
|
|||
|
<code>std::cmp::Ordering</code> into scope from the standard library. Like <code>Result</code>,
|
|||
|
<code>Ordering</code> is another enum, but the variants for <code>Ordering</code> are <code>Less</code>,
|
|||
|
<code>Greater</code>, and <code>Equal</code>. These are the three outcomes that are possible when you
|
|||
|
compare two values.</p>
|
|||
|
<p>Then we add five new lines at the bottom that use the <code>Ordering</code> type. The
|
|||
|
<code>cmp</code> method compares two values and can be called on anything that can be
|
|||
|
compared. It takes a reference to whatever you want to compare with: here it’s
|
|||
|
comparing the <code>guess</code> to the <code>secret_number</code>. Then it returns a variant of the
|
|||
|
<code>Ordering</code> enum we brought into scope with the <code>use</code> statement. We use a
|
|||
|
<a href="ch06-02-match.html"><code>match</code></a><!-- ignore --> expression to decide what to do next based on
|
|||
|
which variant of <code>Ordering</code> was returned from the call to <code>cmp</code> with the values
|
|||
|
in <code>guess</code> and <code>secret_number</code>.</p>
|
|||
|
<p>A <code>match</code> expression is made up of <em>arms</em>. An arm consists of a <em>pattern</em> and
|
|||
|
the code that should be run if the value given to the beginning of the <code>match</code>
|
|||
|
expression fits that arm’s pattern. Rust takes the value given to <code>match</code> and
|
|||
|
looks through each arm’s pattern in turn. The <code>match</code> construct and patterns
|
|||
|
are powerful features in Rust that let you express a variety of situations your
|
|||
|
code might encounter and make sure that you handle them all. These features
|
|||
|
will be covered in detail in Chapter 6 and Chapter 18, respectively.</p>
|
|||
|
<p>Let’s walk through an example of what would happen with the <code>match</code> expression
|
|||
|
used here. Say that the user has guessed 50 and the randomly generated secret
|
|||
|
number this time is 38. When the code compares 50 to 38, the <code>cmp</code> method will
|
|||
|
return <code>Ordering::Greater</code>, because 50 is greater than 38. The <code>match</code>
|
|||
|
expression gets the <code>Ordering::Greater</code> value and starts checking each arm’s
|
|||
|
pattern. It looks at the first arm’s pattern, <code>Ordering::Less</code>, and sees that
|
|||
|
the value <code>Ordering::Greater</code> does not match <code>Ordering::Less</code>, so it ignores
|
|||
|
the code in that arm and moves to the next arm. The next arm’s pattern,
|
|||
|
<code>Ordering::Greater</code>, <em>does</em> match <code>Ordering::Greater</code>! The associated code in
|
|||
|
that arm will execute and print <code>Too big!</code> to the screen. The <code>match</code>
|
|||
|
expression ends because it has no need to look at the last arm in this scenario.</p>
|
|||
|
<p>However, the code in Listing 2-4 won’t compile yet. Let’s try it:</p>
|
|||
|
<pre><code class="language-text">$ cargo build
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
error[E0308]: mismatched types
|
|||
|
--> src/main.rs:23:21
|
|||
|
|
|
|||
|
23 | match guess.cmp(&secret_number) {
|
|||
|
| ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integer
|
|||
|
|
|
|||
|
= note: expected type `&std::string::String`
|
|||
|
= note: found type `&{integer}`
|
|||
|
|
|||
|
error: aborting due to previous error
|
|||
|
Could not compile `guessing_game`.
|
|||
|
</code></pre>
|
|||
|
<p>The core of the error states that there are <em>mismatched types</em>. Rust has a
|
|||
|
strong, static type system. However, it also has type inference. When we wrote
|
|||
|
<code>let mut guess = String::new()</code>, Rust was able to infer that <code>guess</code> should be
|
|||
|
a <code>String</code> and didn’t make us write the type. The <code>secret_number</code>, on the other
|
|||
|
hand, is a number type. A few number types can have a value between 1 and 100:
|
|||
|
<code>i32</code>, a 32-bit number; <code>u32</code>, an unsigned 32-bit number; <code>i64</code>, a 64-bit
|
|||
|
number; as well as others. Rust defaults to an <code>i32</code>, which is the type of
|
|||
|
<code>secret_number</code> unless you add type information elsewhere that would cause Rust
|
|||
|
to infer a different numerical type. The reason for the error is that Rust
|
|||
|
cannot compare a string and a number type.</p>
|
|||
|
<p>Ultimately, we want to convert the <code>String</code> the program reads as input into a
|
|||
|
real number type so we can compare it numerically to the secret number. We can
|
|||
|
do that by adding the following two lines to the <code>main</code> function body:</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">// --snip--
|
|||
|
|
|||
|
let mut guess = String::new();
|
|||
|
|
|||
|
io::stdin().read_line(&mut guess)
|
|||
|
.expect("Failed to read line");
|
|||
|
|
|||
|
let guess: u32 = guess.trim().parse()
|
|||
|
.expect("Please type a number!");
|
|||
|
|
|||
|
println!("You guessed: {}", guess);
|
|||
|
|
|||
|
match guess.cmp(&secret_number) {
|
|||
|
Ordering::Less => println!("Too small!"),
|
|||
|
Ordering::Greater => println!("Too big!"),
|
|||
|
Ordering::Equal => println!("You win!"),
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p>The two new lines are:</p>
|
|||
|
<pre><code class="language-rust ignore">let guess: u32 = guess.trim().parse()
|
|||
|
.expect("Please type a number!");
|
|||
|
</code></pre>
|
|||
|
<p>We create a variable named <code>guess</code>. But wait, doesn’t the program already have
|
|||
|
a variable named <code>guess</code>? It does, but Rust allows us to <em>shadow</em> the previous
|
|||
|
value of <code>guess</code> with a new one. This feature is often used in situations in
|
|||
|
which you want to convert a value from one type to another type. Shadowing lets
|
|||
|
us reuse the <code>guess</code> variable name rather than forcing us to create two unique
|
|||
|
variables, such as <code>guess_str</code> and <code>guess</code> for example. (Chapter 3 covers
|
|||
|
shadowing in more detail.)</p>
|
|||
|
<p>We bind <code>guess</code> to the expression <code>guess.trim().parse()</code>. The <code>guess</code> in the
|
|||
|
expression refers to the original <code>guess</code> that was a <code>String</code> with the input in
|
|||
|
it. The <code>trim</code> method on a <code>String</code> instance will eliminate any whitespace at
|
|||
|
the beginning and end. Although <code>u32</code> can contain only numerical characters,
|
|||
|
the user must press <span class="keystroke">enter</span> to satisfy
|
|||
|
<code>read_line</code>. When the user presses <span class="keystroke">enter</span>, a
|
|||
|
newline character is added to the string. For example, if the user types <span
|
|||
|
class="keystroke">5</span> and presses <span class="keystroke">enter</span>,
|
|||
|
<code>guess</code> looks like this: <code>5\n</code>. The <code>\n</code> represents “newline,” the result of
|
|||
|
pressing <span class="keystroke">enter</span>. The <code>trim</code> method eliminates
|
|||
|
<code>\n</code>, resulting in just <code>5</code>.</p>
|
|||
|
<p>The <a href="../std/primitive.str.html#method.parse"><code>parse</code> method on strings</a><!-- ignore --> parses a string into some
|
|||
|
kind of number. Because this method can parse a variety of number types, we
|
|||
|
need to tell Rust the exact number type we want by using <code>let guess: u32</code>. The
|
|||
|
colon (<code>:</code>) after <code>guess</code> tells Rust we’ll annotate the variable’s type. Rust
|
|||
|
has a few built-in number types; the <code>u32</code> seen here is an unsigned, 32-bit
|
|||
|
integer. It’s a good default choice for a small positive number. You’ll learn
|
|||
|
about other number types in Chapter 3. Additionally, the <code>u32</code> annotation in
|
|||
|
this example program and the comparison with <code>secret_number</code> means that Rust
|
|||
|
will infer that <code>secret_number</code> should be a <code>u32</code> as well. So now the
|
|||
|
comparison will be between two values of the same type!</p>
|
|||
|
<p>The call to <code>parse</code> could easily cause an error. If, for example, the string
|
|||
|
contained <code>A👍%</code>, there would be no way to convert that to a number. Because it
|
|||
|
might fail, the <code>parse</code> method returns a <code>Result</code> type, much as the <code>read_line</code>
|
|||
|
method does (discussed earlier in <a href="#handling-potential-failure-with-the-result-type">“Handling Potential Failure with the
|
|||
|
<code>Result</code> Type”</a><!-- ignore
|
|||
|
-->). We’ll treat this <code>Result</code> the same way by using the <code>expect</code> method
|
|||
|
again. If <code>parse</code> returns an <code>Err</code> <code>Result</code> variant because it couldn’t create
|
|||
|
a number from the string, the <code>expect</code> call will crash the game and print the
|
|||
|
message we give it. If <code>parse</code> can successfully convert the string to a number,
|
|||
|
it will return the <code>Ok</code> variant of <code>Result</code>, and <code>expect</code> will return the
|
|||
|
number that we want from the <code>Ok</code> value.</p>
|
|||
|
<p>Let’s run the program now!</p>
|
|||
|
<pre><code class="language-text">$ cargo run
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Guess the number!
|
|||
|
The secret number is: 58
|
|||
|
Please input your guess.
|
|||
|
76
|
|||
|
You guessed: 76
|
|||
|
Too big!
|
|||
|
</code></pre>
|
|||
|
<p>Nice! Even though spaces were added before the guess, the program still figured
|
|||
|
out that the user guessed 76. Run the program a few times to verify the
|
|||
|
different behavior with different kinds of input: guess the number correctly,
|
|||
|
guess a number that is too high, and guess a number that is too low.</p>
|
|||
|
<p>We have most of the game working now, but the user can make only one guess.
|
|||
|
Let’s change that by adding a loop!</p>
|
|||
|
<h2><a class="header" href="#allowing-multiple-guesses-with-looping" id="allowing-multiple-guesses-with-looping">Allowing Multiple Guesses with Looping</a></h2>
|
|||
|
<p>The <code>loop</code> keyword creates an infinite loop. We’ll add that now to give users
|
|||
|
more chances at guessing the number:</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">// --snip--
|
|||
|
|
|||
|
println!("The secret number is: {}", secret_number);
|
|||
|
|
|||
|
loop {
|
|||
|
println!("Please input your guess.");
|
|||
|
|
|||
|
// --snip--
|
|||
|
|
|||
|
match guess.cmp(&secret_number) {
|
|||
|
Ordering::Less => println!("Too small!"),
|
|||
|
Ordering::Greater => println!("Too big!"),
|
|||
|
Ordering::Equal => println!("You win!"),
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p>As you can see, we’ve moved everything into a loop from the guess input prompt
|
|||
|
onward. Be sure to indent the lines inside the loop another four spaces each
|
|||
|
and run the program again. Notice that there is a new problem because the
|
|||
|
program is doing exactly what we told it to do: ask for another guess forever!
|
|||
|
It doesn’t seem like the user can quit!</p>
|
|||
|
<p>The user could always interrupt the program by using the keyboard shortcut <span
|
|||
|
class="keystroke">ctrl-c</span>. But there’s another way to escape this
|
|||
|
insatiable monster, as mentioned in the <code>parse</code> discussion in <a href="#comparing-the-guess-to-the-secret-number">“Comparing the
|
|||
|
Guess to the Secret Number”</a><!--
|
|||
|
ignore -->: if the user enters a non-number answer, the program will crash. The
|
|||
|
user can take advantage of that in order to quit, as shown here:</p>
|
|||
|
<pre><code class="language-text">$ cargo run
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Finished dev [unoptimized + debuginfo] target(s) in 1.50 secs
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Guess the number!
|
|||
|
The secret number is: 59
|
|||
|
Please input your guess.
|
|||
|
45
|
|||
|
You guessed: 45
|
|||
|
Too small!
|
|||
|
Please input your guess.
|
|||
|
60
|
|||
|
You guessed: 60
|
|||
|
Too big!
|
|||
|
Please input your guess.
|
|||
|
59
|
|||
|
You guessed: 59
|
|||
|
You win!
|
|||
|
Please input your guess.
|
|||
|
quit
|
|||
|
thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:785
|
|||
|
note: Run with `RUST_BACKTRACE=1` for a backtrace.
|
|||
|
error: Process didn't exit successfully: `target/debug/guess` (exit code: 101)
|
|||
|
</code></pre>
|
|||
|
<p>Typing <code>quit</code> actually quits the game, but so will any other non-number input.
|
|||
|
However, this is suboptimal to say the least. We want the game to automatically
|
|||
|
stop when the correct number is guessed.</p>
|
|||
|
<h3><a class="header" href="#quitting-after-a-correct-guess" id="quitting-after-a-correct-guess">Quitting After a Correct Guess</a></h3>
|
|||
|
<p>Let’s program the game to quit when the user wins by adding a <code>break</code> statement:</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">// --snip--
|
|||
|
|
|||
|
match guess.cmp(&secret_number) {
|
|||
|
Ordering::Less => println!("Too small!"),
|
|||
|
Ordering::Greater => println!("Too big!"),
|
|||
|
Ordering::Equal => {
|
|||
|
println!("You win!");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p>Adding the <code>break</code> line after <code>You win!</code> makes the program exit the loop when
|
|||
|
the user guesses the secret number correctly. Exiting the loop also means
|
|||
|
exiting the program, because the loop is the last part of <code>main</code>.</p>
|
|||
|
<h3><a class="header" href="#handling-invalid-input" id="handling-invalid-input">Handling Invalid Input</a></h3>
|
|||
|
<p>To further refine the game’s behavior, rather than crashing the program when
|
|||
|
the user inputs a non-number, let’s make the game ignore a non-number so the
|
|||
|
user can continue guessing. We can do that by altering the line where <code>guess</code>
|
|||
|
is converted from a <code>String</code> to a <code>u32</code>, as shown in Listing 2-5.</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">// --snip--
|
|||
|
|
|||
|
io::stdin().read_line(&mut guess)
|
|||
|
.expect("Failed to read line");
|
|||
|
|
|||
|
let guess: u32 = match guess.trim().parse() {
|
|||
|
Ok(num) => num,
|
|||
|
Err(_) => continue,
|
|||
|
};
|
|||
|
|
|||
|
println!("You guessed: {}", guess);
|
|||
|
|
|||
|
// --snip--
|
|||
|
</code></pre>
|
|||
|
<p><span class="caption">Listing 2-5: Ignoring a non-number guess and asking for
|
|||
|
another guess instead of crashing the program</span></p>
|
|||
|
<p>Switching from an <code>expect</code> call to a <code>match</code> expression is how you generally
|
|||
|
move from crashing on an error to handling the error. Remember that <code>parse</code>
|
|||
|
returns a <code>Result</code> type and <code>Result</code> is an enum that has the variants <code>Ok</code> or
|
|||
|
<code>Err</code>. We’re using a <code>match</code> expression here, as we did with the <code>Ordering</code>
|
|||
|
result of the <code>cmp</code> method.</p>
|
|||
|
<p>If <code>parse</code> is able to successfully turn the string into a number, it will
|
|||
|
return an <code>Ok</code> value that contains the resulting number. That <code>Ok</code> value will
|
|||
|
match the first arm’s pattern, and the <code>match</code> expression will just return the
|
|||
|
<code>num</code> value that <code>parse</code> produced and put inside the <code>Ok</code> value. That number
|
|||
|
will end up right where we want it in the new <code>guess</code> variable we’re creating.</p>
|
|||
|
<p>If <code>parse</code> is <em>not</em> able to turn the string into a number, it will return an
|
|||
|
<code>Err</code> value that contains more information about the error. The <code>Err</code> value
|
|||
|
does not match the <code>Ok(num)</code> pattern in the first <code>match</code> arm, but it does
|
|||
|
match the <code>Err(_)</code> pattern in the second arm. The underscore, <code>_</code>, is a
|
|||
|
catchall value; in this example, we’re saying we want to match all <code>Err</code>
|
|||
|
values, no matter what information they have inside them. So the program will
|
|||
|
execute the second arm’s code, <code>continue</code>, which tells the program to go to the
|
|||
|
next iteration of the <code>loop</code> and ask for another guess. So, effectively, the
|
|||
|
program ignores all errors that <code>parse</code> might encounter!</p>
|
|||
|
<p>Now everything in the program should work as expected. Let’s try it:</p>
|
|||
|
<pre><code class="language-text">$ cargo run
|
|||
|
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
|
|||
|
Running `target/debug/guessing_game`
|
|||
|
Guess the number!
|
|||
|
The secret number is: 61
|
|||
|
Please input your guess.
|
|||
|
10
|
|||
|
You guessed: 10
|
|||
|
Too small!
|
|||
|
Please input your guess.
|
|||
|
99
|
|||
|
You guessed: 99
|
|||
|
Too big!
|
|||
|
Please input your guess.
|
|||
|
foo
|
|||
|
Please input your guess.
|
|||
|
61
|
|||
|
You guessed: 61
|
|||
|
You win!
|
|||
|
</code></pre>
|
|||
|
<p>Awesome! With one tiny final tweak, we will finish the guessing game. Recall
|
|||
|
that the program is still printing the secret number. That worked well for
|
|||
|
testing, but it ruins the game. Let’s delete the <code>println!</code> that outputs the
|
|||
|
secret number. Listing 2-6 shows the final code.</p>
|
|||
|
<p><span class="filename">Filename: src/main.rs</span></p>
|
|||
|
<pre><code class="language-rust ignore">use std::io;
|
|||
|
use std::cmp::Ordering;
|
|||
|
use rand::Rng;
|
|||
|
|
|||
|
fn main() {
|
|||
|
println!("Guess the number!");
|
|||
|
|
|||
|
let secret_number = rand::thread_rng().gen_range(1, 101);
|
|||
|
|
|||
|
loop {
|
|||
|
println!("Please input your guess.");
|
|||
|
|
|||
|
let mut guess = String::new();
|
|||
|
|
|||
|
io::stdin().read_line(&mut guess)
|
|||
|
.expect("Failed to read line");
|
|||
|
|
|||
|
let guess: u32 = match guess.trim().parse() {
|
|||
|
Ok(num) => num,
|
|||
|
Err(_) => continue,
|
|||
|
};
|
|||
|
|
|||
|
println!("You guessed: {}", guess);
|
|||
|
|
|||
|
match guess.cmp(&secret_number) {
|
|||
|
Ordering::Less => println!("Too small!"),
|
|||
|
Ordering::Greater => println!("Too big!"),
|
|||
|
Ordering::Equal => {
|
|||
|
println!("You win!");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</code></pre>
|
|||
|
<p><span class="caption">Listing 2-6: Complete guessing game code</span></p>
|
|||
|
<h2><a class="header" href="#summary" id="summary">Summary</a></h2>
|
|||
|
<p>At this point, you’ve successfully built the guessing game. Congratulations!</p>
|
|||
|
<p>This project was a hands-on way to introduce you to many new Rust concepts:
|
|||
|
<code>let</code>, <code>match</code>, methods, associated functions, the use of external crates, and
|
|||
|
more. In the next few chapters, you’ll learn about these concepts in more
|
|||
|
detail. Chapter 3 covers concepts that most programming languages have, such as
|
|||
|
variables, data types, and functions, and shows how to use them in Rust.
|
|||
|
Chapter 4 explores ownership, a feature that makes Rust different from other
|
|||
|
languages. Chapter 5 discusses structs and method syntax, and Chapter 6
|
|||
|
explains how enums work.</p>
|
|||
|
|
|||
|
</main>
|
|||
|
|
|||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|||
|
<!-- Mobile navigation buttons -->
|
|||
|
|
|||
|
<a rel="prev" href="ch01-03-hello-cargo.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="ch03-00-common-programming-concepts.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 href="ch01-03-hello-cargo.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|||
|
<i class="fa fa-angle-left"></i>
|
|||
|
</a>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<a href="ch03-00-common-programming-concepts.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.playpen_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 -->
|
|||
|
|
|||
|
<script type="text/javascript" src="ferris.js"></script>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</body>
|
|||
|
</html>
|