RustBook/ch12-01-accepting-command-line-arguments.html

346 lines
33 KiB
HTML
Raw Normal View History

2020-01-06 20:57:15 +00:00
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Accepting Command Line Arguments - 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"><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-module-tree.html"><
</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>
<h2><a class="header" href="#accepting-command-line-arguments" id="accepting-command-line-arguments">Accepting Command Line Arguments</a></h2>
<p>Lets create a new project with, as always, <code>cargo new</code>. Well call our project
<code>minigrep</code> to distinguish it from the <code>grep</code> tool that you might already have
on your system.</p>
<pre><code class="language-text">$ cargo new minigrep
Created binary (application) `minigrep` project
$ cd minigrep
</code></pre>
<p>The first task is to make <code>minigrep</code> accept its two command line arguments: the
filename and a string to search for. That is, we want to be able to run our
program with <code>cargo run</code>, a string to search for, and a path to a file to
search in, like so:</p>
<pre><code class="language-text">$ cargo run searchstring example-filename.txt
</code></pre>
<p>Right now, the program generated by <code>cargo new</code> cannot process arguments we
give it. Some existing libraries on <a href="https://crates.io/">crates.io</a> can help
with writing a program that accepts command line arguments, but because youre
just learning this concept, lets implement this capability ourselves.</p>
<h3><a class="header" href="#reading-the-argument-values" id="reading-the-argument-values">Reading the Argument Values</a></h3>
<p>To enable <code>minigrep</code> to read the values of command line arguments we pass to
it, well need a function provided in Rusts standard library, which is
<code>std::env::args</code>. This function returns an iterator of the command line
arguments that were given to <code>minigrep</code>. Well cover iterators fully in
<a href="ch13-00-functional-features.html">Chapter 13</a><!-- ignore -->. For now, you only need to know two details
about iterators: iterators produce a series of values, and we can call the
<code>collect</code> method on an iterator to turn it into a collection, such as a vector,
containing all the elements the iterator produces.</p>
<p>Use the code in Listing 12-1 to allow your <code>minigrep</code> program to read any
command line arguments passed to it and then collect the values into a vector.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">use std::env;
fn main() {
let args: Vec&lt;String&gt; = env::args().collect();
println!(&quot;{:?}&quot;, args);
}
</code></pre></pre>
<p><span class="caption">Listing 12-1: Collecting the command line arguments into
a vector and printing them</span></p>
<p>First, we bring the <code>std::env</code> module into scope with a <code>use</code> statement so we
can use its <code>args</code> function. Notice that the <code>std::env::args</code> function is
nested in two levels of modules. As we discussed in <a href="ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths">Chapter
7</a><!-- ignore -->, in cases where the desired function is
nested in more than one module, its conventional to bring the parent module
into scope rather than the function. By doing so, we can easily use other
functions from <code>std::env</code>. Its also less ambiguous than adding <code>use std::env::args</code> and then calling the function with just <code>args</code>, because <code>args</code>
might easily be mistaken for a function thats defined in the current module.</p>
<blockquote>
<h3><a class="header" href="#the-args-function-and-invalid-unicode" id="the-args-function-and-invalid-unicode">The <code>args</code> Function and Invalid Unicode</a></h3>
<p>Note that <code>std::env::args</code> will panic if any argument contains invalid
Unicode. If your program needs to accept arguments containing invalid
Unicode, use <code>std::env::args_os</code> instead. That function returns an iterator
that produces <code>OsString</code> values instead of <code>String</code> values. Weve chosen to
use <code>std::env::args</code> here for simplicity, because <code>OsString</code> values differ
per platform and are more complex to work with than <code>String</code> values.</p>
</blockquote>
<p>On the first line of <code>main</code>, we call <code>env::args</code>, and we immediately use
<code>collect</code> to turn the iterator into a vector containing all the values produced
by the iterator. We can use the <code>collect</code> function to create many kinds of
collections, so we explicitly annotate the type of <code>args</code> to specify that we
want a vector of strings. Although we very rarely need to annotate types in
Rust, <code>collect</code> is one function you do often need to annotate because Rust
isnt able to infer the kind of collection you want.</p>
<p>Finally, we print the vector using the debug formatter, <code>:?</code>. Lets try running
the code first with no arguments and then with two arguments:</p>
<pre><code class="language-text">$ cargo run
--snip--
[&quot;target/debug/minigrep&quot;]
$ cargo run needle haystack
--snip--
[&quot;target/debug/minigrep&quot;, &quot;needle&quot;, &quot;haystack&quot;]
</code></pre>
<p>Notice that the first value in the vector is <code>&quot;target/debug/minigrep&quot;</code>, which
is the name of our binary. This matches the behavior of the arguments list in
C, letting programs use the name by which they were invoked in their execution.
Its often convenient to have access to the program name in case you want to
print it in messages or change behavior of the program based on what command
line alias was used to invoke the program. But for the purposes of this
chapter, well ignore it and save only the two arguments we need.</p>
<h3><a class="header" href="#saving-the-argument-values-in-variables" id="saving-the-argument-values-in-variables">Saving the Argument Values in Variables</a></h3>
<p>Printing the value of the vector of arguments illustrated that the program is
able to access the values specified as command line arguments. Now we need to
save the values of the two arguments in variables so we can use the values
throughout the rest of the program. We do that in Listing 12-2.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust should_panic">use std::env;
fn main() {
let args: Vec&lt;String&gt; = env::args().collect();
let query = &amp;args[1];
let filename = &amp;args[2];
println!(&quot;Searching for {}&quot;, query);
println!(&quot;In file {}&quot;, filename);
}
</code></pre></pre>
<p><span class="caption">Listing 12-2: Creating variables to hold the query
argument and filename argument</span></p>
<p>As we saw when we printed the vector, the programs name takes up the first
value in the vector at <code>args[0]</code>, so were starting at index <code>1</code>. The first
argument <code>minigrep</code> takes is the string were searching for, so we put a
reference to the first argument in the variable <code>query</code>. The second argument
will be the filename, so we put a reference to the second argument in the
variable <code>filename</code>.</p>
<p>We temporarily print the values of these variables to prove that the code is
working as we intend. Lets run this program again with the arguments <code>test</code>
and <code>sample.txt</code>:</p>
<pre><code class="language-text">$ cargo run test sample.txt
Compiling minigrep v0.1.0 (file:///projects/minigrep)
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt
</code></pre>
<p>Great, the program is working! The values of the arguments we need are being
saved into the right variables. Later well add some error handling to deal
with certain potential erroneous situations, such as when the user provides no
arguments; for now, well ignore that situation and work on adding file-reading
capabilities instead.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch12-00-an-io-project.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="ch12-02-reading-a-file.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="ch12-00-an-io-project.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="ch12-02-reading-a-file.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>