Traits

Contents
Define a trait
Implement it
Default methods
Derive cheap traits

Define a trait

A trait lists method signatures that types can share. It says what behavior looks like without saying how any one type works. Any type that implements every listed method is said to implement the trait.

trait Greeter { fn greet(&self) -> String; }

The greet method borrows the value and returns owned text. No body appears here, so each implementor writes its own version. The next section gives User its version.

Implement it

An impl block ties the trait to one concrete type. The header names both the trait and the type, and the body fills in each method. User stores a name, so greeting formats that name into a sentence.

struct User { name: String, } impl Greeter for User { fn greet(&self) -> String { format!("hello, {}", self.name) } }

Other types can implement Greeter too, each with different text. Code that takes a Greeter works with all of them at once. Shared behavior without shared fields is the whole point of traits.

Default methods

Traits may ship a body for methods that most types want unchanged. Implementors inherit the default and override only what differs. Loud builds on greet, so it converts whatever greet returns.

trait Greeter { fn greet(&self) -> String; fn loud(&self) -> String { self.greet().to_uppercase() } }

A type that implements greet gets loud for free. Types with special needs write their own loud and the default steps aside. Defaults keep traits small while staying flexible.

Derive cheap traits

Some standard traits are so mechanical that the compiler writes them on request. Debug prints values for developers, and Clone duplicates them on demand. One attribute line above the struct enables both at once.

#[derive(Debug, Clone)] struct User { name: String, } fn main() { let user = User { name: String::from("ada") }; println!("{:?}", user.clone()); }

Deriving works only for traits that opt in, which the standard library marks clearly. Debug output uses the {:?} placeholder seen above. Reach for derive before hand writing any obvious impl.

Next: Generics

Article author: Arthur Isaev

Related articles
Rust
Rust course: zero to hero in 50 lessons
What is Rust and where it runs
Install Rust
cargo new
Your first program
Variables
Numbers
Strings
Booleans
Tuples
Arrays
Vectors
Slices
if and else
match
Loops
Ownership
Borrowing
Lifetimes
Functions
Structs
Enums in Rust
Advanced match in Rust
Option combinators in Rust
Result and the question mark in Rust
Advanced strings in Rust
Vec methods in Rust
HashMaps in Rust
Modules in Rust
Crates and workspaces in Rust
Testing in Rust
Error handling
Traits
Generics
Trait bounds
Closures
Iterators
Smart pointers
Threads
Mutex and Arc
Files
CLI arguments
Environment variables
Diagnostics
Time
Parsing strings
TCP networking
Capstone: wordfreq CLI
Capstone: tiny HTTP server
Modern Rust tour
Hero roadmap: the whole course on one page
Install Rust on Windows 11
Install Rust on Ubuntu
Install Rust on Rocky Linux
Install Rust on macOS
Install Rust on FreeBSD
Rust in Docker

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: