easy_rust/Chapter_30.html

400 lines
26 KiB
HTML
Raw Normal View History

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title> Generics - 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> Updates</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" class="active"><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"
</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" 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="generics"><a class="header" href="#generics">Generics</a></h2>
<p>In functions, you write what type to take as input:</p>
<pre><pre class="playground"><code class="language-rust">fn return_number(number: i32) -&gt; i32 {
println!(&quot;Here is your number.&quot;);
number
}
fn main() {
let number = return_number(5);
}
</code></pre></pre>
<p>But what if you want to take more than just <code>i32</code>? You can use generics for this. Generics means &quot;maybe one type, maybe another type&quot;.</p>
<p>For generics, you use angle brackets with the type inside, like this: <code>&lt;T&gt;</code> This means &quot;any type you put into the function&quot;. Usually, generics uses types with one capital letter (T, U, V, etc.), though you don't have to just use one letter.</p>
<p>This is how you change the function to make it generic:</p>
<pre><pre class="playground"><code class="language-rust">fn return_number&lt;T&gt;(number: T) -&gt; T {
println!(&quot;Here is your number.&quot;);
number
}
fn main() {
let number = return_number(5);
}
</code></pre></pre>
<p>The important part is the <code>&lt;T&gt;</code> after the function name. Without this, Rust will think that T is a concrete (concrete = not generic) type, like <code>String</code> or <code>i8</code>.</p>
<p>This is easier to understand if we write out a type name. See what happens when we change <code>T</code> to <code>MyType</code>:</p>
<pre><pre class="playground"><code class="language-rust">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn return_number(number: MyType) -&gt; MyType { // ⚠️
println!(&quot;Here is your number.&quot;);
number
}
<span class="boring">}
</span></code></pre></pre>
<p>As you can see, <code>MyType</code> is concrete, not generic. So we need to write this and so now it works:</p>
<pre><pre class="playground"><code class="language-rust">fn return_number&lt;MyType&gt;(number: MyType) -&gt; MyType {
println!(&quot;Here is your number.&quot;);
number
}
fn main() {
let number = return_number(5);
}
</code></pre></pre>
<p>So the single letter <code>T</code> is for human eyes, but the part after the function name is for the compiler's &quot;eyes&quot;. Without it, it's not generic.</p>
<p>Now we will go back to type <code>T</code>, because Rust code usually uses <code>T</code>.</p>
<p>You will remember that some types in Rust are <strong>Copy</strong>, some are <strong>Clone</strong>, some are <strong>Display</strong>, some are <strong>Debug</strong>, and so on. With <strong>Debug</strong>, we can print with <code>{:?}</code>. So now you can see that we have a problem if we want to print <code>T</code>:</p>
<pre><pre class="playground"><code class="language-rust">fn print_number&lt;T&gt;(number: T) {
println!(&quot;Here is your number: {:?}&quot;, number); // ⚠️
}
fn main() {
print_number(5);
}
</code></pre></pre>
<p><code>print_number</code> needs <strong>Debug</strong> to print <code>number</code>, but is <code>T</code> a type with <code>Debug</code>? Maybe not. Maybe it doesn't have <code>#[derive(Debug)]</code>, who knows. The compiler doesn't know either, so it gives an error:</p>
<pre><code class="language-text">error[E0277]: `T` doesn't implement `std::fmt::Debug`
--&gt; src\main.rs:29:43
|
29 | println!(&quot;Here is your number: {:?}&quot;, number);
| ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
</code></pre>
<p>T doesn't implement <strong>Debug</strong>. So do we implement Debug for T? No, because we don't know what T is. But we can tell the function: &quot;Don't worry, because any type T for this function will have Debug&quot;.</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Debug; // Debug is located at std::fmt::Debug. So now we can just write 'Debug'.
fn print_number&lt;T: Debug&gt;(number: T) { // &lt;T: Debug&gt; is the important part
println!(&quot;Here is your number: {:?}&quot;, number);
}
fn main() {
print_number(5);
}
</code></pre></pre>
<p>So now the compiler knows: &quot;Okay, this type T is going to have Debug&quot;. Now the code works, because <code>i32</code> has Debug. Now we can give it many types: <code>String</code>, <code>&amp;str</code>, and so on, because they all have Debug.</p>
<p>Now we can create a struct and give it Debug with #[derive(Debug)], so now we can print it too. Our function can take <code>i32</code>, the struct Animal, and more:</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Debug;
#[derive(Debug)]
struct Animal {
name: String,
age: u8,
}
fn print_item&lt;T: Debug&gt;(item: T) {
println!(&quot;Here is your item: {:?}&quot;, item);
}
fn main() {
let charlie = Animal {
name: &quot;Charlie&quot;.to_string(),
age: 1,
};
let number = 55;
print_item(charlie);
print_item(number);
}
</code></pre></pre>
<p>This prints:</p>
<pre><code class="language-text">Here is your item: Animal { name: &quot;Charlie&quot;, age: 1 }
Here is your item: 55
</code></pre>
<p>Sometimes we need more than one type in a generic function. We have to write out each type name, and think about how we want to use it. In this example, we want two types. First we want to print a statement for type T. Printing with <code>{}</code> is nicer, so we will require <code>Display</code> for <code>T</code>.</p>
<p>Next is type U, and the two variables <code>num_1</code> and <code>num_2</code> have type U (U is some sort of number). We want to compare them, so we need <code>PartialOrd</code>. That trait lets us use things like <code>&lt;</code>, <code>&gt;</code>, <code>==</code>, and so on. We want to print them too, so we require <code>Display</code> for <code>U</code> as well.</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Display;
use std::cmp::PartialOrd;
fn compare_and_display&lt;T: Display, U: Display + PartialOrd&gt;(statement: T, num_1: U, num_2: U) {
println!(&quot;{}! Is {} greater than {}? {}&quot;, statement, num_1, num_2, num_1 &gt; num_2);
}
fn main() {
compare_and_display(&quot;Listen up!&quot;, 9, 8);
}
</code></pre></pre>
<p>This prints <code>Listen up!! Is 9 greater than 8? true</code>.</p>
<p>So <code>fn compare_and_display&lt;T: Display, U: Display + PartialOrd&gt;(statement: T, num_1: U, num_2: U)</code> says:</p>
<ul>
<li>The function name is <code>compare_and_display</code>,</li>
<li>The first type is T, and it is generic. It must be a type that can print with {}.</li>
<li>The next type is U, and it is generic. It must be a type that can print with {}. Also, it must be a type that can compare (use <code>&gt;</code>, <code>&lt;</code>, and <code>==</code>).</li>
</ul>
<p>Now we can give <code>compare_and_display</code> different types. <code>statement</code> can be a <code>String</code>, a <code>&amp;str</code>, anything with Display.</p>
<p>To make generic functions easier to read, we can also write it like this with <code>where</code> right before the code block:</p>
<pre><pre class="playground"><code class="language-rust">use std::cmp::PartialOrd;
use std::fmt::Display;
fn compare_and_display&lt;T, U&gt;(statement: T, num_1: U, num_2: U)
where
T: Display,
U: Display + PartialOrd,
{
println!(&quot;{}! Is {} greater than {}? {}&quot;, statement, num_1, num_2, num_1 &gt; num_2);
}
fn main() {
compare_and_display(&quot;Listen up!&quot;, 9, 8);
}
</code></pre></pre>
<p>Using <code>where</code> is a good idea when you have many generic types.</p>
<p>Also note:</p>
<ul>
<li>If you have one type T and another type T, they must be the same.</li>
<li>If you have one type T and another type U, they can be different. But they can also be the same.</li>
</ul>
<p>For example:</p>
<pre><pre class="playground"><code class="language-rust">use std::fmt::Display;
fn say_two&lt;T: Display, U: Display&gt;(statement_1: T, statement_2: U) { // Type T needs Display, type U needs Display
println!(&quot;I have two things to say: {} and {}&quot;, statement_1, statement_2);
}
fn main() {
say_two(&quot;Hello there!&quot;, String::from(&quot;I hate sand.&quot;)); // Type T is a &amp;str, but type U is a String.
say_two(String::from(&quot;Where is Padme?&quot;), String::from(&quot;Is she all right?&quot;)); // Both types are String.
}
</code></pre></pre>
<p>This prints:</p>
<pre><code class="language-text">I have two things to say: Hello there! and I hate sand.
I have two things to say: Where is Padme? and Is she all right?
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="Chapter_29.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_31.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_29.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_31.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>