Files
docs-rust/ch10/ch10-02-traits.html
2026-06-22 21:27:36 +05:30

570 lines
32 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Defining Shared Behavior with Traits</title>
</head>
<body>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="traits-defining-shared-behavior"></a></p>
<h2 id="defining-shared-behavior-with-traits"><a class="header" href="#defining-shared-behavior-with-traits">Defining Shared Behavior with Traits</a></h2>
<p>A <em>trait</em> defines the functionality a particular type has and can share with
other types. We can use traits to define shared behavior in an abstract way. We
can use <em>trait bounds</em> to specify that a generic type can be any type that has
certain behavior.</p>
<section class="note" aria-role="note">
<p>Note: Traits are similar to a feature often called <em>interfaces</em> in other
languages, although with some differences.</p>
</section>
<h3 id="defining-a-trait"><a class="header" href="#defining-a-trait">Defining a Trait</a></h3>
<p>A types behavior consists of the methods we can call on that type. Different
types share the same behavior if we can call the same methods on all of those
types. Trait definitions are a way to group method signatures together to
define a set of behaviors necessary to accomplish some purpose.</p>
<p>For example, lets say we have multiple structs that hold various kinds and
amounts of text: a <code>NewsArticle</code> struct that holds a news story filed in a
particular location and a <code>SocialPost</code> that can have, at most, 280 characters
along with metadata that indicates whether it was a new post, a repost, or a
reply to another post.</p>
<p>We want to make a media aggregator library crate named <code>aggregator</code> that can
display summaries of data that might be stored in a <code>NewsArticle</code> or
<code>SocialPost</code> instance. To do this, we need a summary from each type, and well
request that summary by calling a <code>summarize</code> method on an instance. Listing
10-12 shows the definition of a public <code>Summary</code> trait that expresses this
behavior.</p>
<figure class="listing" id="listing-10-12">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">pub trait Summary {
fn summarize(&amp;self) -&gt; String;
}</code></pre>
<figcaption><a href="#listing-10-12">Listing 10-12</a>: A <code>Summary</code> trait that consists of the behavior provided by a <code>summarize</code> method</figcaption>
</figure>
<p>Here, we declare a trait using the <code>trait</code> keyword and then the traits name,
which is <code>Summary</code> in this case. We also declare the trait as <code>pub</code> so that
crates depending on this crate can make use of this trait too, as well see in
a few examples. Inside the curly brackets, we declare the method signatures
that describe the behaviors of the types that implement this trait, which in
this case is <code>fn summarize(&amp;self) -&gt; String</code>.</p>
<p>After the method signature, instead of providing an implementation within curly
brackets, we use a semicolon. Each type implementing this trait must provide
its own custom behavior for the body of the method. The compiler will enforce
that any type that has the <code>Summary</code> trait will have the method <code>summarize</code>
defined with this signature exactly.</p>
<p>A trait can have multiple methods in its body: The method signatures are listed
one per line, and each line ends in a semicolon.</p>
<h3 id="implementing-a-trait-on-a-type"><a class="header" href="#implementing-a-trait-on-a-type">Implementing a Trait on a Type</a></h3>
<p>Now that weve defined the desired signatures of the <code>Summary</code> traits methods,
we can implement it on the types in our media aggregator. Listing 10-13 shows
an implementation of the <code>Summary</code> trait on the <code>NewsArticle</code> struct that uses
the headline, the author, and the location to create the return value of
<code>summarize</code>. For the <code>SocialPost</code> struct, we define <code>summarize</code> as the username
followed by the entire text of the post, assuming that the post content is
already limited to 280 characters.</p>
<figure class="listing" id="listing-10-13">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground"><span class="boring">pub trait Summary {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String;
</span><span class="boring">}
</span><span class="boring">
</span>pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&amp;self) -&gt; String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct SocialPost {
pub username: String,
pub content: String,
pub reply: bool,
pub repost: bool,
}
impl Summary for SocialPost {
fn summarize(&amp;self) -&gt; String {
format!("{}: {}", self.username, self.content)
}
}</code></pre>
<figcaption><a href="#listing-10-13">Listing 10-13</a>: Implementing the <code>Summary</code> trait on the <code>NewsArticle</code> and <code>SocialPost</code> types</figcaption>
</figure>
<p>Implementing a trait on a type is similar to implementing regular methods. The
difference is that after <code>impl</code>, we put the trait name we want to implement,
then use the <code>for</code> keyword, and then specify the name of the type we want to
implement the trait for. Within the <code>impl</code> block, we put the method signatures
that the trait definition has defined. Instead of adding a semicolon after each
signature, we use curly brackets and fill in the method body with the specific
behavior that we want the methods of the trait to have for the particular type.</p>
<p>Now that the library has implemented the <code>Summary</code> trait on <code>NewsArticle</code> and
<code>SocialPost</code>, users of the crate can call the trait methods on instances of
<code>NewsArticle</code> and <code>SocialPost</code> in the same way we call regular methods. The only
difference is that the user must bring the trait into scope as well as the
types. Heres an example of how a binary crate could use our <code>aggregator</code>
library crate:</p>
<pre><code class="language-rust ignore">use aggregator::{SocialPost, Summary};
fn main() {
let post = SocialPost {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
repost: false,
};
println!("1 new post: {}", post.summarize());
}</code></pre>
<p>This code prints <code>1 new post: horse_ebooks: of course, as you probably already know, people</code>.</p>
<p>Other crates that depend on the <code>aggregator</code> crate can also bring the <code>Summary</code>
trait into scope to implement <code>Summary</code> on their own types. One restriction to
note is that we can implement a trait on a type only if either the trait or the
type, or both, are local to our crate. For example, we can implement standard
library traits like <code>Display</code> on a custom type like <code>SocialPost</code> as part of our
<code>aggregator</code> crate functionality because the type <code>SocialPost</code> is local to our
<code>aggregator</code> crate. We can also implement <code>Summary</code> on <code>Vec&lt;T&gt;</code> in our
<code>aggregator</code> crate because the trait <code>Summary</code> is local to our <code>aggregator</code>
crate.</p>
<p>But we cant implement external traits on external types. For example, we cant
implement the <code>Display</code> trait on <code>Vec&lt;T&gt;</code> within our <code>aggregator</code> crate,
because <code>Display</code> and <code>Vec&lt;T&gt;</code> are both defined in the standard library and
arent local to our <code>aggregator</code> crate. This restriction is part of a property
called <em>coherence</em>, and more specifically the <em>orphan rule</em>, so named because
the parent type is not present. This rule ensures that other peoples code
cant break your code and vice versa. Without the rule, two crates could
implement the same trait for the same type, and Rust wouldnt know which
implementation to use.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="default-implementations"></a></p>
<h3 id="using-default-implementations"><a class="header" href="#using-default-implementations">Using Default Implementations</a></h3>
<p>Sometimes its useful to have default behavior for some or all of the methods
in a trait instead of requiring implementations for all methods on every type.
Then, as we implement the trait on a particular type, we can keep or override
each methods default behavior.</p>
<p>In Listing 10-14, we specify a default string for the <code>summarize</code> method of the
<code>Summary</code> trait instead of only defining the method signature, as we did in
Listing 10-12.</p>
<figure class="listing" id="listing-10-14">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">pub trait Summary {
fn summarize(&amp;self) -&gt; String {
String::from("(Read more...)")
}
}
<span class="boring">
</span><span class="boring">pub struct NewsArticle {
</span><span class="boring"> pub headline: String,
</span><span class="boring"> pub location: String,
</span><span class="boring"> pub author: String,
</span><span class="boring"> pub content: String,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for NewsArticle {}
</span><span class="boring">
</span><span class="boring">pub struct SocialPost {
</span><span class="boring"> pub username: String,
</span><span class="boring"> pub content: String,
</span><span class="boring"> pub reply: bool,
</span><span class="boring"> pub repost: bool,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for SocialPost {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}: {}", self.username, self.content)
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
<figcaption><a href="#listing-10-14">Listing 10-14</a>: Defining a <code>Summary</code> trait with a default implementation of the <code>summarize</code> method</figcaption>
</figure>
<p>To use a default implementation to summarize instances of <code>NewsArticle</code>, we
specify an empty <code>impl</code> block with <code>impl Summary for NewsArticle {}</code>.</p>
<p>Even though were no longer defining the <code>summarize</code> method on <code>NewsArticle</code>
directly, weve provided a default implementation and specified that
<code>NewsArticle</code> implements the <code>Summary</code> trait. As a result, we can still call
the <code>summarize</code> method on an instance of <code>NewsArticle</code>, like this:</p>
<pre><code class="language-rust ignore"><span class="boring">use aggregator::{self, NewsArticle, Summary};
</span><span class="boring">
</span><span class="boring">fn main() {
</span> let article = NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from(
"The Pittsburgh Penguins once again are the best \
hockey team in the NHL.",
),
};
println!("New article available! {}", article.summarize());
<span class="boring">}</span></code></pre>
<p>This code prints <code>New article available! (Read more...)</code>.</p>
<p>Creating a default implementation doesnt require us to change anything about
the implementation of <code>Summary</code> on <code>SocialPost</code> in Listing 10-13. The reason is
that the syntax for overriding a default implementation is the same as the
syntax for implementing a trait method that doesnt have a default
implementation.</p>
<p>Default implementations can call other methods in the same trait, even if those
other methods dont have a default implementation. In this way, a trait can
provide a lot of useful functionality and only require implementors to specify
a small part of it. For example, we could define the <code>Summary</code> trait to have a
<code>summarize_author</code> method whose implementation is required, and then define a
<code>summarize</code> method that has a default implementation that calls the
<code>summarize_author</code> method:</p>
<pre><code class="language-rust noplayground">pub trait Summary {
fn summarize_author(&amp;self) -&gt; String;
fn summarize(&amp;self) -&gt; String {
format!("(Read more from {}...)", self.summarize_author())
}
}
<span class="boring">
</span><span class="boring">pub struct SocialPost {
</span><span class="boring"> pub username: String,
</span><span class="boring"> pub content: String,
</span><span class="boring"> pub reply: bool,
</span><span class="boring"> pub repost: bool,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for SocialPost {
</span><span class="boring"> fn summarize_author(&amp;self) -&gt; String {
</span><span class="boring"> format!("@{}", self.username)
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
<p>To use this version of <code>Summary</code>, we only need to define <code>summarize_author</code>
when we implement the trait on a type:</p>
<pre><code class="language-rust ignore"><span class="boring">pub trait Summary {
</span><span class="boring"> fn summarize_author(&amp;self) -&gt; String;
</span><span class="boring">
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("(Read more from {}...)", self.summarize_author())
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct SocialPost {
</span><span class="boring"> pub username: String,
</span><span class="boring"> pub content: String,
</span><span class="boring"> pub reply: bool,
</span><span class="boring"> pub repost: bool,
</span><span class="boring">}
</span><span class="boring">
</span>impl Summary for SocialPost {
fn summarize_author(&amp;self) -&gt; String {
format!("@{}", self.username)
}
}</code></pre>
<p>After we define <code>summarize_author</code>, we can call <code>summarize</code> on instances of the
<code>SocialPost</code> struct, and the default implementation of <code>summarize</code> will call the
definition of <code>summarize_author</code> that weve provided. Because weve implemented
<code>summarize_author</code>, the <code>Summary</code> trait has given us the behavior of the
<code>summarize</code> method without requiring us to write any more code. Heres what
that looks like:</p>
<pre><code class="language-rust ignore"><span class="boring">use aggregator::{self, SocialPost, Summary};
</span><span class="boring">
</span><span class="boring">fn main() {
</span> let post = SocialPost {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
repost: false,
};
println!("1 new post: {}", post.summarize());
<span class="boring">}</span></code></pre>
<p>This code prints <code>1 new post: (Read more from @horse_ebooks...)</code>.</p>
<p>Note that it isnt possible to call the default implementation from an
overriding implementation of that same method.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="traits-as-parameters"></a></p>
<h3 id="using-traits-as-parameters"><a class="header" href="#using-traits-as-parameters">Using Traits as Parameters</a></h3>
<p>Now that you know how to define and implement traits, we can explore how to use
traits to define functions that accept many different types. Well use the
<code>Summary</code> trait we implemented on the <code>NewsArticle</code> and <code>SocialPost</code> types in
Listing 10-13 to define a <code>notify</code> function that calls the <code>summarize</code> method
on its <code>item</code> parameter, which is of some type that implements the <code>Summary</code>
trait. To do this, we use the <code>impl Trait</code> syntax, like this:</p>
<pre><code class="language-rust ignore"><span class="boring">pub trait Summary {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String;
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct NewsArticle {
</span><span class="boring"> pub headline: String,
</span><span class="boring"> pub location: String,
</span><span class="boring"> pub author: String,
</span><span class="boring"> pub content: String,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for NewsArticle {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}, by {} ({})", self.headline, self.author, self.location)
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct SocialPost {
</span><span class="boring"> pub username: String,
</span><span class="boring"> pub content: String,
</span><span class="boring"> pub reply: bool,
</span><span class="boring"> pub repost: bool,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for SocialPost {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}: {}", self.username, self.content)
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span>pub fn notify(item: &amp;impl Summary) {
println!("Breaking news! {}", item.summarize());
}</code></pre>
<p>Instead of a concrete type for the <code>item</code> parameter, we specify the <code>impl</code>
keyword and the trait name. This parameter accepts any type that implements the
specified trait. In the body of <code>notify</code>, we can call any methods on <code>item</code>
that come from the <code>Summary</code> trait, such as <code>summarize</code>. We can call <code>notify</code>
and pass in any instance of <code>NewsArticle</code> or <code>SocialPost</code>. Code that calls the
function with any other type, such as a <code>String</code> or an <code>i32</code>, wont compile,
because those types dont implement <code>Summary</code>.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="fixing-the-largest-function-with-trait-bounds"></a></p>
<h4 id="trait-bound-syntax"><a class="header" href="#trait-bound-syntax">Trait Bound Syntax</a></h4>
<p>The <code>impl Trait</code> syntax works for straightforward cases but is actually syntax
sugar for a longer form known as a <em>trait bound</em>; it looks like this:</p>
<pre><code class="language-rust ignore">pub fn notify&lt;T: Summary&gt;(item: &amp;T) {
println!("Breaking news! {}", item.summarize());
}</code></pre>
<p>This longer form is equivalent to the example in the previous section but is
more verbose. We place trait bounds with the declaration of the generic type
parameter after a colon and inside angle brackets.</p>
<p>The <code>impl Trait</code> syntax is convenient and makes for more concise code in simple
cases, while the fuller trait bound syntax can express more complexity in other
cases. For example, we can have two parameters that implement <code>Summary</code>. Doing
so with the <code>impl Trait</code> syntax looks like this:</p>
<pre><code class="language-rust ignore">pub fn notify(item1: &amp;impl Summary, item2: &amp;impl Summary) {</code></pre>
<p>Using <code>impl Trait</code> is appropriate if we want this function to allow <code>item1</code> and
<code>item2</code> to have different types (as long as both types implement <code>Summary</code>). If
we want to force both parameters to have the same type, however, we must use a
trait bound, like this:</p>
<pre><code class="language-rust ignore">pub fn notify&lt;T: Summary&gt;(item1: &amp;T, item2: &amp;T) {</code></pre>
<p>The generic type <code>T</code> specified as the type of the <code>item1</code> and <code>item2</code>
parameters constrains the function such that the concrete type of the value
passed as an argument for <code>item1</code> and <code>item2</code> must be the same.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="specifying-multiple-trait-bounds-with-the--syntax"></a></p>
<h4 id="multiple-trait-bounds-with-the--syntax"><a class="header" href="#multiple-trait-bounds-with-the--syntax">Multiple Trait Bounds with the <code>+</code> Syntax</a></h4>
<p>We can also specify more than one trait bound. Say we wanted <code>notify</code> to use
display formatting as well as <code>summarize</code> on <code>item</code>: We specify in the <code>notify</code>
definition that <code>item</code> must implement both <code>Display</code> and <code>Summary</code>. We can do
so using the <code>+</code> syntax:</p>
<pre><code class="language-rust ignore">pub fn notify(item: &amp;(impl Summary + Display)) {</code></pre>
<p>The <code>+</code> syntax is also valid with trait bounds on generic types:</p>
<pre><code class="language-rust ignore">pub fn notify&lt;T: Summary + Display&gt;(item: &amp;T) {</code></pre>
<p>With the two trait bounds specified, the body of <code>notify</code> can call <code>summarize</code>
and use <code>{}</code> to format <code>item</code>.</p>
<h4 id="clearer-trait-bounds-with-where-clauses"><a class="header" href="#clearer-trait-bounds-with-where-clauses">Clearer Trait Bounds with <code>where</code> Clauses</a></h4>
<p>Using too many trait bounds has its downsides. Each generic has its own trait
bounds, so functions with multiple generic type parameters can contain lots of
trait bound information between the functions name and its parameter list,
making the function signature hard to read. For this reason, Rust has alternate
syntax for specifying trait bounds inside a <code>where</code> clause after the function
signature. So, instead of writing this:</p>
<pre><code class="language-rust ignore">fn some_function&lt;T: Display + Clone, U: Clone + Debug&gt;(t: &amp;T, u: &amp;U) -&gt; i32 {</code></pre>
<p>we can use a <code>where</code> clause, like this:</p>
<pre><code class="language-rust ignore">fn some_function&lt;T, U&gt;(t: &amp;T, u: &amp;U) -&gt; i32
where
T: Display + Clone,
U: Clone + Debug,
{
<span class="boring"> unimplemented!()
</span><span class="boring">}</span></code></pre>
<p>This functions signature is less cluttered: The function name, parameter list,
and return type are close together, similar to a function without lots of trait
bounds.</p>
<h3 id="returning-types-that-implement-traits"><a class="header" href="#returning-types-that-implement-traits">Returning Types That Implement Traits</a></h3>
<p>We can also use the <code>impl Trait</code> syntax in the return position to return a
value of some type that implements a trait, as shown here:</p>
<pre><code class="language-rust ignore"><span class="boring">pub trait Summary {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String;
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct NewsArticle {
</span><span class="boring"> pub headline: String,
</span><span class="boring"> pub location: String,
</span><span class="boring"> pub author: String,
</span><span class="boring"> pub content: String,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for NewsArticle {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}, by {} ({})", self.headline, self.author, self.location)
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct SocialPost {
</span><span class="boring"> pub username: String,
</span><span class="boring"> pub content: String,
</span><span class="boring"> pub reply: bool,
</span><span class="boring"> pub repost: bool,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for SocialPost {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}: {}", self.username, self.content)
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span>fn returns_summarizable() -&gt; impl Summary {
SocialPost {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
repost: false,
}
}</code></pre>
<p>By using <code>impl Summary</code> for the return type, we specify that the
<code>returns_summarizable</code> function returns some type that implements the <code>Summary</code>
trait without naming the concrete type. In this case, <code>returns_summarizable</code>
returns a <code>SocialPost</code>, but the code calling this function doesnt need to know
that.</p>
<p>The ability to specify a return type only by the trait it implements is
especially useful in the context of closures and iterators, which we cover in
Chapter 13. Closures and iterators create types that only the compiler knows or
types that are very long to specify. The <code>impl Trait</code> syntax lets you concisely
specify that a function returns some type that implements the <code>Iterator</code> trait
without needing to write out a very long type.</p>
<p>However, you can only use <code>impl Trait</code> if youre returning a single type. For
example, this code that returns either a <code>NewsArticle</code> or a <code>SocialPost</code> with
the return type specified as <code>impl Summary</code> wouldnt work:</p>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">pub trait Summary {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String;
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct NewsArticle {
</span><span class="boring"> pub headline: String,
</span><span class="boring"> pub location: String,
</span><span class="boring"> pub author: String,
</span><span class="boring"> pub content: String,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for NewsArticle {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}, by {} ({})", self.headline, self.author, self.location)
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">pub struct SocialPost {
</span><span class="boring"> pub username: String,
</span><span class="boring"> pub content: String,
</span><span class="boring"> pub reply: bool,
</span><span class="boring"> pub repost: bool,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Summary for SocialPost {
</span><span class="boring"> fn summarize(&amp;self) -&gt; String {
</span><span class="boring"> format!("{}: {}", self.username, self.content)
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span>fn returns_summarizable(switch: bool) -&gt; impl Summary {
if switch {
NewsArticle {
headline: String::from(
"Penguins win the Stanley Cup Championship!",
),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from(
"The Pittsburgh Penguins once again are the best \
hockey team in the NHL.",
),
}
} else {
SocialPost {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
repost: false,
}
}
}</code></pre>
<p>Returning either a <code>NewsArticle</code> or a <code>SocialPost</code> isnt allowed due to
restrictions around how the <code>impl Trait</code> syntax is implemented in the compiler.
Well cover how to write a function with this behavior in the <a href="../ch18/ch18-02-trait-objects.html#using-trait-objects-to-abstract-over-shared-behavior">“Using Trait
Objects to Abstract over Shared Behavior”</a><!-- ignore -->
section of Chapter 18.</p>
<h3 id="using-trait-bounds-to-conditionally-implement-methods"><a class="header" href="#using-trait-bounds-to-conditionally-implement-methods">Using Trait Bounds to Conditionally Implement Methods</a></h3>
<p>By using a trait bound with an <code>impl</code> block that uses generic type parameters,
we can implement methods conditionally for types that implement the specified
traits. For example, the type <code>Pair&lt;T&gt;</code> in Listing 10-15 always implements the
<code>new</code> function to return a new instance of <code>Pair&lt;T&gt;</code> (recall from the <a href="../ch05/ch05-03-method-syntax.html#method-syntax">“Method
Syntax”</a><!-- ignore --> section of Chapter 5 that <code>Self</code> is a type
alias for the type of the <code>impl</code> block, which in this case is <code>Pair&lt;T&gt;</code>). But
in the next <code>impl</code> block, <code>Pair&lt;T&gt;</code> only implements the <code>cmp_display</code> method if
its inner type <code>T</code> implements the <code>PartialOrd</code> trait that enables comparison
<em>and</em> the <code>Display</code> trait that enables printing.</p>
<figure class="listing" id="listing-10-15">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">use std::fmt::Display;
struct Pair&lt;T&gt; {
x: T,
y: T,
}
impl&lt;T&gt; Pair&lt;T&gt; {
fn new(x: T, y: T) -&gt; Self {
Self { x, y }
}
}
impl&lt;T: Display + PartialOrd&gt; Pair&lt;T&gt; {
fn cmp_display(&amp;self) {
if self.x &gt;= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}</code></pre>
<figcaption><a href="#listing-10-15">Listing 10-15</a>: Conditionally implementing methods on a generic type depending on trait bounds</figcaption>
</figure>
<p>We can also conditionally implement a trait for any type that implements
another trait. Implementations of a trait on any type that satisfies the trait
bounds are called <em>blanket implementations</em> and are used extensively in the
Rust standard library. For example, the standard library implements the
<code>ToString</code> trait on any type that implements the <code>Display</code> trait. The <code>impl</code>
block in the standard library looks similar to this code:</p>
<pre><code class="language-rust ignore">impl&lt;T: Display&gt; ToString for T {
// --snip--
}</code></pre>
<p>Because the standard library has this blanket implementation, we can call the
<code>to_string</code> method defined by the <code>ToString</code> trait on any type that implements
the <code>Display</code> trait. For example, we can turn integers into their corresponding
<code>String</code> values like this because integers implement <code>Display</code>:</p>
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let s = 3.to_string();
<span class="boring">}</span></code></pre>
<p>Blanket implementations appear in the documentation for the trait in the
“Implementors” section.</p>
<p>Traits and trait bounds let us write code that uses generic type parameters to
reduce duplication but also specify to the compiler that we want the generic
type to have particular behavior. The compiler can then use the trait bound
information to check that all the concrete types used with our code provide the
correct behavior. In dynamically typed languages, we would get an error at
runtime if we called a method on a type that didnt define the method. But Rust
moves these errors to compile time so that were forced to fix the problems
before our code is even able to run. Additionally, we dont have to write code
that checks for behavior at runtime, because weve already checked at compile
time. Doing so improves performance without having to give up the flexibility
of generics.</p>
</body>
</html>