RustBook/ch10-01-syntax.html

617 lines
45 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>Generic Data Types - 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="#generic-data-types" id="generic-data-types">Generic Data Types</a></h2>
<p>We can use generics to create definitions for items like function signatures or
structs, which we can then use with many different concrete data types. Lets
first look at how to define functions, structs, enums, and methods using
generics. Then well discuss how generics affect code performance.</p>
<h3><a class="header" href="#in-function-definitions" id="in-function-definitions">In Function Definitions</a></h3>
<p>When defining a function that uses generics, we place the generics in the
signature of the function where we would usually specify the data types of the
parameters and return value. Doing so makes our code more flexible and provides
more functionality to callers of our function while preventing code duplication.</p>
<p>Continuing with our <code>largest</code> function, Listing 10-4 shows two functions that
both find the largest value in a slice.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">fn largest_i32(list: &amp;[i32]) -&gt; i32 {
let mut largest = list[0];
for &amp;item in list.iter() {
if item &gt; largest {
largest = item;
}
}
largest
}
fn largest_char(list: &amp;[char]) -&gt; char {
let mut largest = list[0];
for &amp;item in list.iter() {
if item &gt; largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest_i32(&amp;number_list);
println!(&quot;The largest number is {}&quot;, result);
<span class="boring"> assert_eq!(result, 100);
</span>
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest_char(&amp;char_list);
println!(&quot;The largest char is {}&quot;, result);
<span class="boring"> assert_eq!(result, 'y');
</span>}
</code></pre></pre>
<p><span class="caption">Listing 10-4: Two functions that differ only in their
names and the types in their signatures</span></p>
<p>The <code>largest_i32</code> function is the one we extracted in Listing 10-3 that finds
the largest <code>i32</code> in a slice. The <code>largest_char</code> function finds the largest
<code>char</code> in a slice. The function bodies have the same code, so lets eliminate
the duplication by introducing a generic type parameter in a single function.</p>
<p>To parameterize the types in the new function well define, we need to name the
type parameter, just as we do for the value parameters to a function. You can
use any identifier as a type parameter name. But well use <code>T</code> because, by
convention, parameter names in Rust are short, often just a letter, and Rusts
type-naming convention is CamelCase. Short for “type,” <code>T</code> is the default
choice of most Rust programmers.</p>
<p>When we use a parameter in the body of the function, we have to declare the
parameter name in the signature so the compiler knows what that name means.
Similarly, when we use a type parameter name in a function signature, we have
to declare the type parameter name before we use it. To define the generic
<code>largest</code> function, place type name declarations inside angle brackets, <code>&lt;&gt;</code>,
between the name of the function and the parameter list, like this:</p>
<pre><code class="language-rust ignore">fn largest&lt;T&gt;(list: &amp;[T]) -&gt; T {
</code></pre>
<p>We read this definition as: the function <code>largest</code> is generic over some type
<code>T</code>. This function has one parameter named <code>list</code>, which is a slice of values
of type <code>T</code>. The <code>largest</code> function will return a value of the same type <code>T</code>.</p>
<p>Listing 10-5 shows the combined <code>largest</code> function definition using the generic
data type in its signature. The listing also shows how we can call the function
with either a slice of <code>i32</code> values or <code>char</code> values. Note that this code wont
compile yet, but well fix it later in this chapter.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">fn largest&lt;T&gt;(list: &amp;[T]) -&gt; T {
let mut largest = list[0];
for &amp;item in list.iter() {
if item &gt; largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&amp;number_list);
println!(&quot;The largest number is {}&quot;, result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&amp;char_list);
println!(&quot;The largest char is {}&quot;, result);
}
</code></pre>
<p><span class="caption">Listing 10-5: A definition of the <code>largest</code> function that
uses generic type parameters but doesnt compile yet</span></p>
<p>If we compile this code right now, well get this error:</p>
<pre><code class="language-text">error[E0369]: binary operation `&gt;` cannot be applied to type `T`
--&gt; src/main.rs:5:12
|
5 | if item &gt; largest {
| ^^^^^^^^^^^^^^
|
= note: an implementation of `std::cmp::PartialOrd` might be missing for `T`
</code></pre>
<p>The note mentions <code>std::cmp::PartialOrd</code>, which is a <em>trait</em>. Well talk about
traits in the next section. For now, this error states that the body of
<code>largest</code> wont work for all possible types that <code>T</code> could be. Because we want
to compare values of type <code>T</code> in the body, we can only use types whose values
can be ordered. To enable comparisons, the standard library has the
<code>std::cmp::PartialOrd</code> trait that you can implement on types (see Appendix C
for more on this trait). Youll learn how to specify that a generic type has a
particular trait in the <a href="ch10-02-traits.html#traits-as-parameters">“Traits as Parameters”</a><!--
ignore --> section, but lets first explore other ways of using generic type
parameters.</p>
<h3><a class="header" href="#in-struct-definitions" id="in-struct-definitions">In Struct Definitions</a></h3>
<p>We can also define structs to use a generic type parameter in one or more
fields using the <code>&lt;&gt;</code> syntax. Listing 10-6 shows how to define a <code>Point&lt;T&gt;</code>
struct to hold <code>x</code> and <code>y</code> coordinate values of any type.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">struct Point&lt;T&gt; {
x: T,
y: T,
}
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}
</code></pre></pre>
<p><span class="caption">Listing 10-6: A <code>Point&lt;T&gt;</code> struct that holds <code>x</code> and <code>y</code>
values of type <code>T</code></span></p>
<p>The syntax for using generics in struct definitions is similar to that used in
function definitions. First, we declare the name of the type parameter inside
angle brackets just after the name of the struct. Then we can use the generic
type in the struct definition where we would otherwise specify concrete data
types.</p>
<p>Note that because weve used only one generic type to define <code>Point&lt;T&gt;</code>, this
definition says that the <code>Point&lt;T&gt;</code> struct is generic over some type <code>T</code>, and
the fields <code>x</code> and <code>y</code> are <em>both</em> that same type, whatever that type may be. If
we create an instance of a <code>Point&lt;T&gt;</code> that has values of different types, as in
Listing 10-7, our code wont compile.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">struct Point&lt;T&gt; {
x: T,
y: T,
}
fn main() {
let wont_work = Point { x: 5, y: 4.0 };
}
</code></pre>
<p><span class="caption">Listing 10-7: The fields <code>x</code> and <code>y</code> must be the same
type because both have the same generic data type <code>T</code>.</span></p>
<p>In this example, when we assign the integer value 5 to <code>x</code>, we let the
compiler know that the generic type <code>T</code> will be an integer for this instance of
<code>Point&lt;T&gt;</code>. Then when we specify 4.0 for <code>y</code>, which weve defined to have the
same type as <code>x</code>, well get a type mismatch error like this:</p>
<pre><code class="language-text">error[E0308]: mismatched types
--&gt; src/main.rs:7:38
|
7 | let wont_work = Point { x: 5, y: 4.0 };
| ^^^ expected integer, found
floating-point number
|
= note: expected type `{integer}`
found type `{float}`
</code></pre>
<p>To define a <code>Point</code> struct where <code>x</code> and <code>y</code> are both generics but could have
different types, we can use multiple generic type parameters. For example, in
Listing 10-8, we can change the definition of <code>Point</code> to be generic over types
<code>T</code> and <code>U</code> where <code>x</code> is of type <code>T</code> and <code>y</code> is of type <code>U</code>.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">struct Point&lt;T, U&gt; {
x: T,
y: U,
}
fn main() {
let both_integer = Point { x: 5, y: 10 };
let both_float = Point { x: 1.0, y: 4.0 };
let integer_and_float = Point { x: 5, y: 4.0 };
}
</code></pre></pre>
<p><span class="caption">Listing 10-8: A <code>Point&lt;T, U&gt;</code> generic over two types so
that <code>x</code> and <code>y</code> can be values of different types</span></p>
<p>Now all the instances of <code>Point</code> shown are allowed! You can use as many generic
type parameters in a definition as you want, but using more than a few makes
your code hard to read. When you need lots of generic types in your code, it
could indicate that your code needs restructuring into smaller pieces.</p>
<h3><a class="header" href="#in-enum-definitions" id="in-enum-definitions">In Enum Definitions</a></h3>
<p>As we did with structs, we can define enums to hold generic data types in their
variants. Lets take another look at the <code>Option&lt;T&gt;</code> enum that the standard
library provides, which we used in Chapter 6:</p>
<pre><pre class="playpen"><code class="language-rust">
<span class="boring">#![allow(unused_variables)]
</span><span class="boring">fn main() {
</span>enum Option&lt;T&gt; {
Some(T),
None,
}
<span class="boring">}
</span></code></pre></pre>
<p>This definition should now make more sense to you. As you can see, <code>Option&lt;T&gt;</code>
is an enum that is generic over type <code>T</code> and has two variants: <code>Some</code>, which
holds one value of type <code>T</code>, and a <code>None</code> variant that doesnt hold any value.
By using the <code>Option&lt;T&gt;</code> enum, we can express the abstract concept of having an
optional value, and because <code>Option&lt;T&gt;</code> is generic, we can use this abstraction
no matter what the type of the optional value is.</p>
<p>Enums can use multiple generic types as well. The definition of the <code>Result</code>
enum that we used in Chapter 9 is one example:</p>
<pre><pre class="playpen"><code class="language-rust">
<span class="boring">#![allow(unused_variables)]
</span><span class="boring">fn main() {
</span>enum Result&lt;T, E&gt; {
Ok(T),
Err(E),
}
<span class="boring">}
</span></code></pre></pre>
<p>The <code>Result</code> enum is generic over two types, <code>T</code> and <code>E</code>, and has two variants:
<code>Ok</code>, which holds a value of type <code>T</code>, and <code>Err</code>, which holds a value of type
<code>E</code>. This definition makes it convenient to use the <code>Result</code> enum anywhere we
have an operation that might succeed (return a value of some type <code>T</code>) or fail
(return an error of some type <code>E</code>). In fact, this is what we used to open a
file in Listing 9-3, where <code>T</code> was filled in with the type <code>std::fs::File</code> when
the file was opened successfully and <code>E</code> was filled in with the type
<code>std::io::Error</code> when there were problems opening the file.</p>
<p>When you recognize situations in your code with multiple struct or enum
definitions that differ only in the types of the values they hold, you can
avoid duplication by using generic types instead.</p>
<h3><a class="header" href="#in-method-definitions" id="in-method-definitions">In Method Definitions</a></h3>
<p>We can implement methods on structs and enums (as we did in Chapter 5) and use
generic types in their definitions, too. Listing 10-9 shows the <code>Point&lt;T&gt;</code>
struct we defined in Listing 10-6 with a method named <code>x</code> implemented on it.</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">struct Point&lt;T&gt; {
x: T,
y: T,
}
impl&lt;T&gt; Point&lt;T&gt; {
fn x(&amp;self) -&gt; &amp;T {
&amp;self.x
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!(&quot;p.x = {}&quot;, p.x());
}
</code></pre></pre>
<p><span class="caption">Listing 10-9: Implementing a method named <code>x</code> on the
<code>Point&lt;T&gt;</code> struct that will return a reference to the <code>x</code> field of type
<code>T</code></span></p>
<p>Here, weve defined a method named <code>x</code> on <code>Point&lt;T&gt;</code> that returns a reference
to the data in the field <code>x</code>.</p>
<p>Note that we have to declare <code>T</code> just after <code>impl</code> so we can use it to specify
that were implementing methods on the type <code>Point&lt;T&gt;</code>. By declaring <code>T</code> as a
generic type after <code>impl</code>, Rust can identify that the type in the angle
brackets in <code>Point</code> is a generic type rather than a concrete type.</p>
<p>We could, for example, implement methods only on <code>Point&lt;f32&gt;</code> instances rather
than on <code>Point&lt;T&gt;</code> instances with any generic type. In Listing 10-10 we use the
concrete type <code>f32</code>, meaning we dont declare any types after <code>impl</code>.</p>
<pre><pre class="playpen"><code class="language-rust">
<span class="boring">#![allow(unused_variables)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Point&lt;T&gt; {
</span><span class="boring"> x: T,
</span><span class="boring"> y: T,
</span><span class="boring">}
</span><span class="boring">
</span>impl Point&lt;f32&gt; {
fn distance_from_origin(&amp;self) -&gt; f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Listing 10-10: An <code>impl</code> block that only applies to a
struct with a particular concrete type for the generic type parameter <code>T</code></span></p>
<p>This code means the type <code>Point&lt;f32&gt;</code> will have a method named
<code>distance_from_origin</code> and other instances of <code>Point&lt;T&gt;</code> where <code>T</code> is not of
type <code>f32</code> will not have this method defined. The method measures how far our
point is from the point at coordinates (0.0, 0.0) and uses mathematical
operations that are available only for floating point types.</p>
<p>Generic type parameters in a struct definition arent always the same as those
you use in that structs method signatures. For example, Listing 10-11 defines
the method <code>mixup</code> on the <code>Point&lt;T, U&gt;</code> struct from Listing 10-8. The method
takes another <code>Point</code> as a parameter, which might have different types from the
<code>self</code> <code>Point</code> were calling <code>mixup</code> on. The method creates a new <code>Point</code>
instance with the <code>x</code> value from the <code>self</code> <code>Point</code> (of type <code>T</code>) and the <code>y</code>
value from the passed-in <code>Point</code> (of type <code>W</code>).</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">struct Point&lt;T, U&gt; {
x: T,
y: U,
}
impl&lt;T, U&gt; Point&lt;T, U&gt; {
fn mixup&lt;V, W&gt;(self, other: Point&lt;V, W&gt;) -&gt; Point&lt;T, W&gt; {
Point {
x: self.x,
y: other.y,
}
}
}
fn main() {
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: &quot;Hello&quot;, y: 'c'};
let p3 = p1.mixup(p2);
println!(&quot;p3.x = {}, p3.y = {}&quot;, p3.x, p3.y);
}
</code></pre></pre>
<p><span class="caption">Listing 10-11: A method that uses different generic types
from its structs definition</span></p>
<p>In <code>main</code>, weve defined a <code>Point</code> that has an <code>i32</code> for <code>x</code> (with value <code>5</code>)
and an <code>f64</code> for <code>y</code> (with value <code>10.4</code>). The <code>p2</code> variable is a <code>Point</code> struct
that has a string slice for <code>x</code> (with value <code>&quot;Hello&quot;</code>) and a <code>char</code> for <code>y</code>
(with value <code>c</code>). Calling <code>mixup</code> on <code>p1</code> with the argument <code>p2</code> gives us <code>p3</code>,
which will have an <code>i32</code> for <code>x</code>, because <code>x</code> came from <code>p1</code>. The <code>p3</code> variable
will have a <code>char</code> for <code>y</code>, because <code>y</code> came from <code>p2</code>. The <code>println!</code> macro
call will print <code>p3.x = 5, p3.y = c</code>.</p>
<p>The purpose of this example is to demonstrate a situation in which some generic
parameters are declared with <code>impl</code> and some are declared with the method
definition. Here, the generic parameters <code>T</code> and <code>U</code> are declared after <code>impl</code>,
because they go with the struct definition. The generic parameters <code>V</code> and <code>W</code>
are declared after <code>fn mixup</code>, because theyre only relevant to the method.</p>
<h3><a class="header" href="#performance-of-code-using-generics" id="performance-of-code-using-generics">Performance of Code Using Generics</a></h3>
<p>You might be wondering whether there is a runtime cost when youre using
generic type parameters. The good news is that Rust implements generics in such
a way that your code doesnt run any slower using generic types than it would
with concrete types.</p>
<p>Rust accomplishes this by performing monomorphization of the code that is using
generics at compile time. <em>Monomorphization</em> is the process of turning generic
code into specific code by filling in the concrete types that are used when
compiled.</p>
<p>In this process, the compiler does the opposite of the steps we used to create
the generic function in Listing 10-5: the compiler looks at all the places
where generic code is called and generates code for the concrete types the
generic code is called with.</p>
<p>Lets look at how this works with an example that uses the standard librarys
<code>Option&lt;T&gt;</code> enum:</p>
<pre><pre class="playpen"><code class="language-rust">
<span class="boring">#![allow(unused_variables)]
</span><span class="boring">fn main() {
</span>let integer = Some(5);
let float = Some(5.0);
<span class="boring">}
</span></code></pre></pre>
<p>When Rust compiles this code, it performs monomorphization. During that
process, the compiler reads the values that have been used in <code>Option&lt;T&gt;</code>
instances and identifies two kinds of <code>Option&lt;T&gt;</code>: one is <code>i32</code> and the other
is <code>f64</code>. As such, it expands the generic definition of <code>Option&lt;T&gt;</code> into
<code>Option_i32</code> and <code>Option_f64</code>, thereby replacing the generic definition with
the specific ones.</p>
<p>The monomorphized version of the code looks like the following. The generic
<code>Option&lt;T&gt;</code> is replaced with the specific definitions created by the compiler:</p>
<p><span class="filename">Filename: src/main.rs</span></p>
<pre><pre class="playpen"><code class="language-rust">enum Option_i32 {
Some(i32),
None,
}
enum Option_f64 {
Some(f64),
None,
}
fn main() {
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
}
</code></pre></pre>
<p>Because Rust compiles generic code into code that specifies the type in each
instance, we pay no runtime cost for using generics. When the code runs, it
performs just as it would if we had duplicated each definition by hand. The
process of monomorphization makes Rusts generics extremely efficient at
runtime.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch10-00-generics.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="ch10-02-traits.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="ch10-00-generics.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="ch10-02-traits.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>