Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


x-i18n: generated_at: “2026-03-01T14:07:14Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: 705ae11758c687175e47104a302a9b5f694d04d683bffc28dcc61ffe9a0dc80e source_path: ch10-02-traits.md workflow: 16

使用特征定义共享行为 (Defining Shared Behavior with Traits)

Defining Shared Behavior with Traits

“特征 (trait)” 定义了特定类型具有并可以与其他类型共享的功能。我们可以使用特征以抽象的方式定义共享行为。我们可以使用“特征约束 (trait bounds)”来指定泛型类型可以是任何具有某些行为的类型。

A trait 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 trait bounds to specify that a generic type can be any type that has certain behavior.

注意:特征类似于其他语言中通常称为“接口 (interfaces)”的功能,尽管有一些区别。

Note: Traits are similar to a feature often called interfaces in other languages, although with some differences.

定义特征 (Defining a Trait)

Defining a Trait

一个类型的行为由我们可以在该类型上调用的方法组成。如果我们可以对所有这些类型调用相同的方法,那么不同的类型就共享相同的行为。特征定义是将方法签名组合在一起,以定义完成某些目的所需的一组行为的一种方式。

A type’s 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.

例如,假设我们有多个持有各种种类和数量文本的结构体:一个持有在特定地点提交的新闻报道的 NewsArticle 结构体,以及一个最多可包含 280 个字符的 SocialPost,连同指示它是新发布、转发还是对另一发布的回复的元数据。

For example, let’s say we have multiple structs that hold various kinds and amounts of text: a NewsArticle struct that holds a news story filed in a particular location and a SocialPost 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.

我们想制作一个名为 aggregator 的媒体聚合库 crate,它可以显示可能存储在 NewsArticleSocialPost 实例中的数据摘要。为此,我们需要每个类型的摘要,我们将通过在实例上调用 summarize 方法来请求该摘要。示例 10-12 展示了表达这种行为的公共 Summary 特征的定义。

We want to make a media aggregator library crate named aggregator that can display summaries of data that might be stored in a NewsArticle or SocialPost instance. To do this, we need a summary from each type, and we’ll request that summary by calling a summarize method on an instance. Listing 10-12 shows the definition of a public Summary trait that expresses this behavior.

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-12/src/lib.rs}}

在这里,我们使用 trait 关键字声明一个特征,然后是特征的名称,在此例中为 Summary。我们还将该特征声明为 pub,以便依赖此 crate 的 crate 也可以使用此特征,正如我们将在几个示例中看到的那样。在花括号内,我们声明了方法签名,这些签名描述了实现此特征的类型的行为,在此例中是 fn summarize(&self) -> String

Here, we declare a trait using the trait keyword and then the trait’s name, which is Summary in this case. We also declare the trait as pub so that crates depending on this crate can make use of this trait too, as we’ll 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 fn summarize(&self) -> String.

在方法签名之后,我们不是在花括号内提供实现,而是使用分号。每个实现此特征的类型必须为方法体提供自己的自定义行为。编译器将强制要求任何具有 Summary 特征的类型都必须精确地定义具有此签名的方法 summarize

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 Summary trait will have the method summarize defined with this signature exactly.

一个特征在其主体中可以有多个方法:方法签名每行罗列一个,且每行以分号结尾。

A trait can have multiple methods in its body: The method signatures are listed one per line, and each line ends in a semicolon.

在类型上实现特征 (Implementing a Trait on a Type)

既然我们已经定义了 Summary 特征所需的方法签名,我们就可以在媒体聚合器中的类型上实现它。示例 10-13 展示了在 NewsArticle 结构体上实现 Summary 特征,它使用标题、作者和地点来创建 summarize 的返回值。对于 SocialPost 结构体,我们将 summarize 定义为用户名后跟帖子的全部文本,假设帖子内容已被限制在 280 个字符以内。

Now that we’ve defined the desired signatures of the Summary trait’s methods, we can implement it on the types in our media aggregator. Listing 10-13 shows an implementation of the Summary trait on the NewsArticle struct that uses the headline, the author, and the location to create the return value of summarize. For the SocialPost struct, we define summarize as the username followed by the entire text of the post, assuming that the post content is already limited to 280 characters.

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-13/src/lib.rs:here}}

在类型上实现特征与实现常规方法类似。区别在于在 impl 之后,我们放入想要实现的特征名称,然后使用 for 关键字,接着指定我们想要为其实现特征的类型的名称。在 impl 块内,我们放入特征定义中定义的方法签名。我们不是在每个签名后添加分号,而是使用花括号,并在其中填充特征的方法针对该特定类型所应具有的具体行为。

Implementing a trait on a type is similar to implementing regular methods. The difference is that after impl, we put the trait name we want to implement, then use the for keyword, and then specify the name of the type we want to implement the trait for. Within the impl 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.

现在库已经在 NewsArticleSocialPost 上实现了 Summary 特征,crate 的使用者可以像我们调用常规方法一样,在 NewsArticleSocialPost 的实例上调用特征方法。唯一的区别是使用者必须将特征以及类型都引入作用域。这里有一个二进制 crate 如何使用我们的 aggregator 库 crate 的例子:

Now that the library has implemented the Summary trait on NewsArticle and SocialPost, users of the crate can call the trait methods on instances of NewsArticle and SocialPost 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. Here’s an example of how a binary crate could use our aggregator library crate:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-01-calling-trait-method/src/main.rs}}

这段代码会打印 1 new post: horse_ebooks: of course, as you probably already know, people

This code prints 1 new post: horse_ebooks: of course, as you probably already know, people.

依赖 aggregator crate 的其他 crate 也可以将 Summary 特征引入作用域,以便在它们自己的类型上实现 Summary。需要注意的一个限制是,只有当特征或类型(或两者)对我们的 crate 是本地的时,我们才能在类型上实现该特征。例如,我们可以将标准库特征(如 Display)实现在自定义类型(如 SocialPost)上,作为我们 aggregator crate 功能的一部分,因为类型 SocialPost 对于我们的 aggregator crate 是本地的。我们也可以在我们的 aggregator crate 中为 Vec<T> 实现 Summary ,因为特征 Summary 对于我们的 aggregator crate 是本地的。

Other crates that depend on the aggregator crate can also bring the Summary trait into scope to implement Summary 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 Display on a custom type like SocialPost as part of our aggregator crate functionality because the type SocialPost is local to our aggregator crate. We can also implement Summary on Vec<T> in our aggregator crate because the trait Summary is local to our aggregator crate.

但我们不能在外部类型上实现外部特征。例如,我们不能在我们的 aggregator crate 中为 Vec<T> 实现 Display 特征,因为 DisplayVec<T> 都定义在标准库中,且对我们的 aggregator crate 不是本地的。此限制是被称为“相干性 (coherence)”属性的一部分,更具体地说是“孤儿规则 (orphan rule)”,之所以这样命名是因为父类型不存在。此规则确保他人的代码不会破坏你的代码,反之亦然。如果没有这条规则,两个 crate 可能会为同一个类型实现相同的特征,而 Rust 将不知道该使用哪个实现。

But we can’t implement external traits on external types. For example, we can’t implement the Display trait on Vec<T> within our aggregator crate, because Display and Vec<T> are both defined in the standard library and aren’t local to our aggregator crate. This restriction is part of a property called coherence, and more specifically the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa. Without the rule, two crates could implement the same trait for the same type, and Rust wouldn’t know which implementation to use.

使用默认实现 (Using Default Implementations)

Using Default Implementations

有时为特征中的某些或所有方法提供默认行为很有用,而不是要求在每个类型上都实现所有方法。然后,当我们为特定类型实现该特征时,我们可以保留或覆盖每个方法的默认行为。

Sometimes it’s 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 method’s default behavior.

在示例 10-14 中,我们为 Summary 特征的 summarize 方法指定了一个默认字符串,而不是像在示例 10-12 中那样仅定义方法签名。

In Listing 10-14, we specify a default string for the summarize method of the Summary trait instead of only defining the method signature, as we did in Listing 10-12.

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-14/src/lib.rs:here}}

要使用默认实现来对 NewsArticle 实例进行摘要,我们指定一个空的 impl 块:impl Summary for NewsArticle {}

To use a default implementation to summarize instances of NewsArticle, we specify an empty impl block with impl Summary for NewsArticle {}.

尽管我们不再直接在 NewsArticle 上定义 summarize 方法,但我们提供了一个默认实现,并指定了 NewsArticle 实现了 Summary 特征。因此,我们仍然可以在 NewsArticle 实例上调用 summarize 方法,如下所示:

Even though we’re no longer defining the summarize method on NewsArticle directly, we’ve provided a default implementation and specified that NewsArticle implements the Summary trait. As a result, we can still call the summarize method on an instance of NewsArticle, like this:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-02-calling-default-impl/src/main.rs:here}}

这段代码会打印 New article available! (Read more...)

This code prints New article available! (Read more...).

创建默认实现并不需要我们更改示例 10-13 中 SocialPostSummary 的实现。原因是覆盖默认实现的语法与实现没有默认实现的特征方法的语法相同。

Creating a default implementation doesn’t require us to change anything about the implementation of Summary on SocialPost 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 doesn’t have a default implementation.

默认实现可以调用同一特征中的其他方法,即使那些其他方法没有默认实现。通过这种方式,特征可以提供许多有用的功能,并且只要求实现者指定其中的一小部分。例如,我们可以将 Summary 特征定义为具有一个必须实现的 summarize_author 方法,然后定义一个具有调用 summarize_author 方法的默认实现的 summarize 方法:

Default implementations can call other methods in the same trait, even if those other methods don’t 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 Summary trait to have a summarize_author method whose implementation is required, and then define a summarize method that has a default implementation that calls the summarize_author method:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/lib.rs:here}}

要使用这个版本的 Summary ,我们只需要在为类型实现特征时定义 summarize_author

To use this version of Summary, we only need to define summarize_author when we implement the trait on a type:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/lib.rs:impl}}

在我们定义了 summarize_author 之后,我们就可以在 SocialPost 结构体的实例上调用 summarize,并且 summarize 的默认实现将调用我们提供的 summarize_author 定义。因为我们实现了 summarize_authorSummary 特征就给了我们 summarize 方法的行为,而不需要我们再编写任何代码。它看起来是这样的:

After we define summarize_author, we can call summarize on instances of the SocialPost struct, and the default implementation of summarize will call the definition of summarize_author that we’ve provided. Because we’ve implemented summarize_author, the Summary trait has given us the behavior of the summarize method without requiring us to write any more code. Here’s what that looks like:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-03-default-impl-calls-other-methods/src/main.rs:here}}

这段代码会打印 1 new post: (Read more from @horse_ebooks...)

This code prints 1 new post: (Read more from @horse_ebooks...).

请注意,无法从同一方法的覆盖实现中调用默认实现。

Note that it isn’t possible to call the default implementation from an overriding implementation of that same method.

特征作为参数 (Using Traits as Parameters)

Using Traits as Parameters

既然你知道了如何定义和实现特征,我们可以探索如何使用特征来定义接受许多不同类型的函数。我们将使用在示例 10-13 中为 NewsArticleSocialPost 类型实现的 Summary 特征,来定义一个 notify 函数,该函数对其 item 参数调用 summarize 方法,该参数属于实现了 Summary 特征的某种类型。为此,我们使用 impl Trait 语法,如下所示:

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. We’ll use the Summary trait we implemented on the NewsArticle and SocialPost types in Listing 10-13 to define a notify function that calls the summarize method on its item parameter, which is of some type that implements the Summary trait. To do this, we use the impl Trait syntax, like this:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-04-traits-as-parameters/src/lib.rs:here}}

我们不是为 item 参数指定具体类型,而是指定 impl 关键字和特征名称。此参数接受实现了指定特征的任何类型。在 notify 主体内,我们可以对 item 调用任何来自 Summary 特征的方法,例如 summarize。我们可以调用 notify 并传入 NewsArticleSocialPost 的任何实例。使用任何其他类型(例如 Stringi32)调用该函数的代码将无法通过编译,因为这些类型没有实现 Summary

Instead of a concrete type for the item parameter, we specify the impl keyword and the trait name. This parameter accepts any type that implements the specified trait. In the body of notify, we can call any methods on item that come from the Summary trait, such as summarize. We can call notify and pass in any instance of NewsArticle or SocialPost. Code that calls the function with any other type, such as a String or an i32, won’t compile, because those types don’t implement Summary.

特征约束语法 (Trait Bound Syntax)

Trait Bound Syntax

impl Trait 语法适用于简单情况,但实际上它是被称为“特征约束 (trait bound)”的较长形式的语法糖;它看起来像这样:

pub fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

这种较长形式与前一节中的示例等效,但更冗长。我们将特征约束与泛型类型参数的声明放在一起,位于冒号之后且在尖括号内。

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.

impl Trait 语法在简单情况下很方便且能使代码更简洁,而更完整的特征约束语法可以在其他情况下表达更多的复杂性。例如,我们可以有两个实现了 Summary 的参数。使用 impl Trait 语法如下所示:

The impl Trait 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 Summary. Doing so with the impl Trait syntax looks like this:

pub fn notify(item1: &impl Summary, item2: &impl Summary) {

如果我们希望此函数允许 item1item2 具有不同的类型(只要两种类型都实现了 Summary),使用 impl Trait 是合适的。然而,如果我们想强制两个参数具有相同的类型,我们必须使用特征约束,如下所示:

Using impl Trait is appropriate if we want this function to allow item1 and item2 to have different types (as long as both types implement Summary). If we want to force both parameters to have the same type, however, we must use a trait bound, like this:

pub fn notify<T: Summary>(item1: &T, item2: &T) {

泛型类型 T 被指定为 item1item2 参数的类型,它约束了该函数,使得作为 item1item2 的实参传入的值的具体类型必须相同。

The generic type T specified as the type of the item1 and item2 parameters constrains the function such that the concrete type of the value passed as an argument for item1 and item2 must be the same.

使用 + 语法指定多个特征约束 (Multiple Trait Bounds with the + Syntax)

Multiple Trait Bounds with the + Syntax

我们也可以指定多个特征约束。假设我们希望 notifyitem 上使用显示格式化以及 summarize:我们在 notify 定义中指定 item 必须同时实现 DisplaySummary。我们可以使用 + 语法来做到这一点:

pub fn notify(item: &(impl Summary + Display)) {

+ 语法也适用于泛型类型的特征约束:

pub fn notify<T: Summary + Display>(item: &T) {

通过指定这两个特征约束,notify 的主体就可以调用 summarize 并使用 {} 来格式化 item

With the two trait bounds specified, the body of notify can call summarize and use {} to format item.

使用 where 子句实现更清晰的特征约束 (Clearer Trait Bounds with where Clauses)

Clearer Trait Bounds with where Clauses

使用过多的特征约束也有其缺点。每个泛型都有其自己的特征约束,因此具有多个泛型类型参数的函数可能在函数名和参数列表之间包含大量的特征约束信息,使得函数签名难以阅读。出于这个原因,Rust 有另一种语法,用于在函数签名之后的 where 子句中指定特征约束。所以,与其这样写:

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 function’s 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 where clause after the function signature. So, instead of writing this:

fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {

我们可以使用 where 子句,如下所示:

we can use a where clause, like this:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-07-where-clause/src/lib.rs:here}}

这个函数的签名不那么拥挤了:函数名、参数列表和返回类型都靠得很近,类似于一个没有大量特征约束的函数。

This function’s signature is less cluttered: The function name, parameter list, and return type are close together, similar to a function without lots of trait bounds.

返回实现了特征的类型 (Returning Types That Implement Traits)

Returning Types That Implement Traits

我们也可以在返回位置使用 impl Trait 语法来返回实现了某个特征的某种类型的值,如下所示:

We can also use the impl Trait syntax in the return position to return a value of some type that implements a trait, as shown here:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-05-returning-impl-trait/src/lib.rs:here}}

通过在返回类型中使用 impl Summary ,我们指定 returns_summarizable 函数返回某种实现了 Summary 特征的类型,而不必指明具体类型。在这种情况下,returns_summarizable 返回一个 SocialPost ,但调用该函数的代码不需要知道这一点。

By using impl Summary for the return type, we specify that the returns_summarizable function returns some type that implements the Summary trait without naming the concrete type. In this case, returns_summarizable returns a SocialPost, but the code calling this function doesn’t need to know that.

仅通过其实现的特征来指定返回类型的能力,在闭包和迭代器的语境中特别有用,我们将在第 13 章介绍。闭包和迭代器创建了只有编译器知道的类型,或者是指定起来非常长的类型。impl Trait 语法让你能简洁地指定一个函数返回某种实现了 Iterator 特征的类型,而无需写出非常长的类型名称。

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 impl Trait syntax lets you concisely specify that a function returns some type that implements the Iterator trait without needing to write out a very long type.

然而,只有当你返回单一类型时,才能使用 impl Trait。例如,这段返回 NewsArticleSocialPost 的代码,如果其返回类型被指定为 impl Summary ,将无法工作:

However, you can only use impl Trait if you’re returning a single type. For example, this code that returns either a NewsArticle or a SocialPost with the return type specified as impl Summary wouldn’t work:

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/no-listing-06-impl-trait-returns-one-type/src/lib.rs:here}}

由于编译器中关于 impl Trait 语法实现方式的限制,不允许返回 NewsArticleSocialPost。我们将在第 18 章的“使用特征对象实现不同类型间的抽象行为”部分介绍如何编写具有此行为的函数。

Returning either a NewsArticle or a SocialPost isn’t allowed due to restrictions around how the impl Trait syntax is implemented in the compiler. We’ll cover how to write a function with this behavior in the “Using Trait Objects to Abstract over Shared Behavior” section of Chapter 18.

使用特征约束有条件地实现方法 (Using Trait Bounds to Conditionally Implement Methods)

Using Trait Bounds to Conditionally Implement Methods

通过在带有泛型类型参数的 impl 块中使用特征约束,我们可以为实现了指定特征的类型有条件地实现方法。例如,示例 10-15 中的 Pair<T> 类型总是实现 new 函数以返回 Pair<T> 的新实例(回想第 5 章“方法语法”部分,Selfimpl 块类型的类型别名,在此例中为 Pair<T>)。但在下一个 impl 块中,Pair<T> 只有在其内部类型 T 实现了支持比较的 PartialOrd 特征“以及”支持打印的 Display 特征时,才会实现 cmp_display 方法。

By using a trait bound with an impl block that uses generic type parameters, we can implement methods conditionally for types that implement the specified traits. For example, the type Pair<T> in Listing 10-15 always implements the new function to return a new instance of Pair<T> (recall from the “Method Syntax” section of Chapter 5 that Self is a type alias for the type of the impl block, which in this case is Pair<T>). But in the next impl block, Pair<T> only implements the cmp_display method if its inner type T implements the PartialOrd trait that enables comparison and the Display trait that enables printing.

{{#rustdoc_include ../listings/ch10-generic-types-traits-and-lifetimes/listing-10-15/src/lib.rs}}

我们也可以为实现了另一个特征的任何类型有条件地实现一个特征。对满足特征约束的任何类型实现的特征被称为“覆盖实现 (blanket implementations)”,这在 Rust 标准库中被广泛使用。例如,标准库为任何实现了 Display 特征的类型实现了 ToString 特征。标准库中的 impl 块看起来类似于这段代码:

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 blanket implementations and are used extensively in the Rust standard library. For example, the standard library implements the ToString trait on any type that implements the Display trait. The impl block in the standard library looks similar to this code:

impl<T: Display> ToString for T {
    // --snip--
}

因为标准库有这种覆盖实现,所以我们可以在任何实现了 Display 特征的类型上调用由 ToString 特征定义的 to_string 方法。例如,我们可以像这样将整数转换为它们对应的 String 值,因为整数实现了 Display

Because the standard library has this blanket implementation, we can call the to_string method defined by the ToString trait on any type that implements the Display trait. For example, we can turn integers into their corresponding String values like this because integers implement Display:

#![allow(unused)]
fn main() {
let s = 3.to_string();
}

覆盖实现出现在特征文档的 “Implementors” 部分。

Blanket implementations appear in the documentation for the trait in the “Implementors” section.

特征和特征约束让我们能编写使用泛型类型参数来减少重复的代码,同时也向编译器指定我们希望泛型类型具有特定的行为。编译器随后可以使用特征约束信息来检查与我们代码一起使用的所有具体类型是否都提供了正确的行为。在动态类型语言中,如果我们对一个没有定义该方法的类型调用方法,我们会在运行时得到一个错误。但 Rust 将这些错误移至编译时,因此我们被迫在代码甚至能够运行之前就修复问题。此外,我们不必编写在运行时检查行为的代码,因为我们已经在编译时检查过了。这样做在提高性能的同时,也不必放弃泛型的灵活性。

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 didn’t define the method. But Rust moves these errors to compile time so that we’re forced to fix the problems before our code is even able to run. Additionally, we don’t have to write code that checks for behavior at runtime, because we’ve already checked at compile time. Doing so improves performance without having to give up the flexibility of generics.