Skip to content
You are reading v0.1, which is not the current release. Go to v0.4.

Traits

Traits describe behavior that types can provide and generic code can require. Trait declarations, implementations, associated types, supertraits, and bounds all use the same statically checked type system.

pub trait Named {
fn name(self) -> String;
}

General form:

pub? trait Name<TypeParams>? (: Trait + Trait ...)? {
TraitItem*
}

A trait item is a function declaration or associated type declaration.

Required method:

pub trait Named {
fn name(self) -> String;
}

Default method body:

pub trait Named {
fn name(self) -> String;
fn greeting(self) -> String {
"Hello, ${self.name()}"
}
}

A semicolon declares a required signature. A block supplies a default implementation.

pub trait Ord: Eq {
fn cmp(self, other: Self) -> Ordering;
}

Several supertraits use +:

pub trait Persisted: Eq + Show {
fn id(self) -> Int;
}

An implementation of the child trait must satisfy the supertrait requirements.

Declare an associated type:

pub trait Iterator {
type Item;
fn next(self) -> Step<Self, Self::Item>;
}

With a bound:

pub trait Iterator {
type Item: Show;
fn next(self) -> Step<Self, Self::Item>;
}

Supply it in an implementation:

impl Iterator for Users {
type Item = User;
fn next(self) -> Step<Users, User> {
// ...
}
}
impl Named for User {
fn name(self) -> String {
self.name
}
}

General form:

impl<TypeParams>? TraitType for TargetType {
TraitItem*
}

A trait implementation provides the methods and associated types required by the trait.

impl<A: Show> Show for Box<A> {
fn show(self) -> String {
self.value.show()
}
}

The type parameters after impl are scoped to the implementation block.

An impl without for defines methods belonging directly to the target type:

impl User {
fn normalized_name(self) -> String {
self.name |> String::trim
}
pub fn display_name(self) -> String {
self.normalized_name()
}
}

General form:

impl<TypeParams>? TargetType {
fn ...
pub fn ...
}

A public inherent method uses pub. Trait methods are reached through the trait contract rather than separately exported implementation members.

fn equal<A: Eq>(left: A, right: A) -> Bool {
left == right
}

Several bounds:

fn render<A: Eq + Show>(value: A) -> String {
value.show()
}

Bounds are trait paths separated by +.

Inside a trait, Self names the implementing type:

pub trait Combine {
fn combine(self, other: Self) -> Self;
}

Traits participate in method and operator resolution only where the relevant trait is in scope:

import std::core::{Eq};
let same = left == right;

This keeps the meaning of trait-provided behavior tied to explicit module imports rather than a process-wide registry.

derive(Eq, Ord, Show, Hash, Decode, Encode)
pub type User = {
id: Int,
name: String,
};

The compiler can derive those six structural traits when every field supports the requested behavior. A derive(...) clause appears immediately before its type declaration. Decode and Encode are std::schema’s: the declaration is the schema, and User::schema() reads one from untrusted input.

pub trait Convert<A> {
fn convert(self) -> A;
}

Trait parameters use the normal generic parameter syntax, including bounds, const parameters, and variance where meaningful.

See Generics for parameter forms and Declarations for the top-level grammar shared by traits and implementations.

Khora 0.1.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource