Learn about Traits in Rust

Tram Ho

1. Introduction

Traits is a concept in Rust, similar to interfaces in other programming languages, although with a number of differences.

Each data type will have a number of methods defined and only variables of that data type can be called. If we want to share a method that many types can share, customizing each type, we will need to use traits .

Here we have two structs NewArticle and Tweet with different data fields, both of which need a summarize method to summarize the data.

We define traits with the trait keyword, followed by Summary (the trait’s name). The summarize function returns the type String . Like functions in interfaces in some other languages, functions in traits end with a ; and no function body. Because it is just a prototype for other data types to implement.

2. Implement Trait

Implement trait with data type

Now it’s time to implement summarize method on 2 struct NewsArticle and Tweet .

Implementing a trait for a data type is similar to implementing a regular method for that data type. The only difference is that after the impl keyword will be the name of the trait you want to use and then the for keyword.

Now that the library has implemented the NewsArticle and Tweet Summary trait, users of the bucket can call the trait methods on NewsArticle and Tweet instances in the same way we call regular methods. The only difference is that the user has to include the trait in the scope as well as the types. Here is an example of how binaries can use our composite library:

We have just implemented the Summary trait implementation for two types NewsArticle and Tweet . Now, we can call the summarize method from NewsArticle or Tweet instances like normal methods. Of course, depending on whether the instance is of type NewsArticle or Tweet , the corresponding summarize function will be executed.

Default Implementations

Sometimes it is useful to have default behavior for some or all of the methods in a trait rather than requiring implementations for all methods on every type. Then when we implement the trait on a particular type, we can keep or override the default behavior of each method.

Sometimes we will need a generic default method with types instead of having to implement methods on each of the different types. Then, if we want to change depending on the data type, we can choose the override option.

The default method can call other methods with the same trait , even if the method is only in prototype form. This feature will provide many useful things, let’s take a look at the example below:

Instead of returning a fixed string like in the previous example, the summarize method by calling summarize_author customizes the Tweet’s author name in the returned results.

Trait as parameter

We already know how to define and implement trait above. In addition, trait can also act as a parameter in a function when defined with the impl keyword as follows:

Instead of defining the struct data type to be passed to NewArticle or Tweet , for example, we will replace it with &impl . The input parameter of the function will then receive all data types that implement trait Summary. If passing a data type that does not implement trait , the compiler will report an error.

Trait Bound Syntax

On how to define trait as a function parameter as above, we can use the generic syntax as follows:

In case the function has many trait parameters, these will look like code that looks much more concise

<T: Summary> implies that T only accepts data types for the implementation trait Summary

Use the + . operator

What if you want the input parameter to be a data type that implements multiple trait at the same time? We will use the math +

Input data type requires to implement both trait

Use where . keyword

When defining multiple generic data types plus each type needs to implement many trait , the definition syntax using + sign is somewhat cumbersome when suddenly extending the function definition line.

Instead, we can use the where keyword, the definition of the necessary trait will be brought down to the second line, making the code look neater and cleaner than in the above example.

3. Return type trait

Trait can be defined as return type in a function, let’s see the example below.

Of course the return data type needs to implement trait Summary

However, you can only use Impl Trait if you are returning a single type. The example below returns NewsArticle or Tweet will give an error

References

Traits: Defining Shared Behavior

Share the news now

Source : Viblo