Skip to content
Pre-Release: Fe is under active development. This documentation covers the upcoming release. Follow progress on GitHub

Implementing Traits

Once a trait is defined, types can implement it to provide the required behavior. This is done with the impl Trait for Type syntax.

Implement a trait for a struct:

trait Greetable {
fn greet(self) -> String
}
struct Person {
name: String,
}
impl Greetable for Person {
fn greet(self) -> String {
self.name
}
}

Now Person has the greet method:

let person = Person { name: String {} }
let greeting: String = person.greet() // "Alice"

You must implement every method declared in the trait:

trait Shape {
fn area(self) -> u256
fn perimeter(self) -> u256
}
struct Rectangle {
width: u256,
height: u256,
}
impl Shape for Rectangle {
fn area(self) -> u256 {
self.width * self.height
}
fn perimeter(self) -> u256 {
2 * (self.width + self.height)
}
}

Missing any method causes a compile error:

impl Shape for Rectangle {
fn area(self) -> u256 {
self.width * self.height
}
// Error: missing implementation for `perimeter`
}

Different types can implement the same trait:

trait Area {
fn area(self) -> u256
}
struct Rectangle {
width: u256,
height: u256,
}
struct Circle {
radius: u256,
}
struct Triangle {
base: u256,
height: u256,
}
impl Area for Rectangle {
fn area(self) -> u256 {
self.width * self.height
}
}
impl Area for Circle {
fn area(self) -> u256 {
// Simplified: using 3 * radius^2 as approximation
3 * self.radius * self.radius
}
}
impl Area for Triangle {
fn area(self) -> u256 {
self.base * self.height / 2
}
}

A type can implement multiple traits:

trait Printable {
fn to_string(self) -> String
}
trait Hashable {
fn hash(self) -> u256
}
trait Comparable {
fn equals(self, other: Self) -> bool
}
struct Token {
id: u256,
value: u256,
}
impl Printable for Token {
fn to_string(self) -> String {
String {}
}
}
impl Hashable for Token {
fn hash(self) -> u256 {
self.id
}
}
impl Comparable for Token {
fn equals(self, other: Self) -> bool {
self.id == other.id && self.value == other.value
}
}

For methods with mut self, the implementation can modify the struct:

trait Counter {
fn count(self) -> u256
fn increment(mut self)
fn reset(mut self)
}
struct SimpleCounter {
value: u256,
}
impl Counter for SimpleCounter {
fn count(self) -> u256 {
self.value
}
fn increment(mut self) {
self.value += 1
}
fn reset(mut self) {
self.value = 0
}
}

Self in the implementation refers to the concrete type:

trait Duplicatable {
fn duplicate(self) -> Self
}
struct Point {
x: u256,
y: u256,
}
impl Duplicatable for Point {
fn duplicate(self) -> Self { // Self is Point here
Point {
x: self.x,
y: self.y,
}
}
}

A type can have both trait methods and regular methods:

struct Wallet {
balance: u256,
}
// Regular impl block with methods
impl Wallet {
fn new(initial: u256) -> Wallet {
Wallet { balance: initial }
}
fn deposit(mut self, amount: u256) -> Self {
self.balance += amount
self
}
}
// Trait implementation
trait Printable {
fn to_string(self) -> String
}
impl Printable for Wallet {
fn to_string(self) -> String {
String {}
}
}

Both are available on the type:

let wallet = Wallet::new(100) // Associated function
let wallet = wallet.deposit(50) // Regular method
let s = wallet.to_string() // Trait method

Trait implementations follow the trait’s visibility:

// Public trait
pub trait Serializable {
fn serialize(self) -> u256
}
// Implementation is also effectively public
struct MyType {
value: u256,
}
impl Serializable for MyType {
fn serialize(self) -> u256 {
self.value
}
}
SyntaxDescription
impl Trait for Type { }Implement trait for type
All methods requiredMust implement every trait method
SelfRefers to the implementing type
Multiple traitsA type can implement many traits
Multiple typesMany types can implement same trait