Skip to content

Traits

One line: A trait is how one piece of code talks about many types at once — and it is the feature the rest of Rust is built out of, which is why Copy, Display, Iterator, From and Default all turn up long before anybody explains what they have in common.

Rust has no classes and no inheritance. What it has instead is this: a type declares its data, an impl block gives that type its own functions, and a trait names behaviour that any number of unrelated types can promise to provide. Everything a generic function knows about its argument, it knows because a trait bound said so.

The section starts from the declaration and works outward — what goes in a trait, how a call finds it, and what happens when a function has to return one.

Lesson Level What it teaches
What a trait is 101 → 201 The declaration itself: abstract methods, default bodies, associated constants, and Self — plus why it is neither a base class nor quite an interface
When the impl does not match the trait 201 The trait owns the signature and the impl owns the body: what an impl may change (a parameter's name, mut, a looser bound), the code for each thing it may not — E0046, E0407, E0053, E0050, E0185/E0186, E0276, E0449 — and the E0053 help: line that fixes the arrow and leaves the body broken
A trait must be in scope 201 The use that makes the methods appear, E0599 when it is missing, and the three spellings of one call — including the fully-qualified form that is the only way past an inherent method of the same name
Method resolution 201 How x.f() is actually found: deref to build a candidate list, then U / &U / &mut U at each rung — and the inherent method on a Deref wrapper that silently shadows the target's
"No method named …" 201 The other three things E0599 means: the method nobody wrote, the trait nobody implemented, and the blanket impl whose bound your type misses — told apart by the help: line, which is absent in the first case and names the wrong trait in the last
Extension traits 201 A trait you declare, implemented for a type std owns: E0116 and the two escapes its help: line names, the orphan rule as a permission rather than an obstacle, the blanket impl that reaches every iterator ever written, and the inherent method that beats yours with no warning of any kind
Operators are traits 201 a + b is Add::add(a, b): type Output letting + change the type, the four separate impls one * can need, why 3 * p is not free once p * 3 exists, and the test for whether an operator should exist at all
Returning a trait 201 Why -> Trait cannot compile, impl Trait when one type comes back, Box<dyn Trait> when several can, and the second pointer that makes &dyn sixteen bytes
Static vs dynamic dispatch 201 → 301 <P: Trait> vs &dyn Trait: monomorphization against a vtable, the heterogeneous collection that decides it, the enum that gets you one without either, the type check dyn never performs, and E0038 — which the compiler now calls dyn compatibility and every book still calls object safety
Supertraits 201 trait Shout: Display is a bound, not a parent — what the default bodies may spend, the E0277 that lands on the impl line, and trait upcasting, stable since 1.86
Marker traits 201 Traits with no methods: Sized as the bound you never wrote, ?Sized, Send/Sync as auto traits nobody implements, and PhantomData
Phantom types 201 → 301 A type parameter with no data behind it: E0392 and the PhantomData field that answers it, what the field claims about variance and drop, impl Ballot<Star> as a specialization for one tag, and the three things the tag costs you
Drop, and what RAII buys 201 The destructor that runs at a place you can point to: three drop orders, two of them opposites, E0040 on an explicit call, and the let _ = that releases a guard before the work starts
ToOwned 201 Clone generalized to borrowed data: why str cannot be Clone at all, why .clone() on a &str quietly does nothing, and the Rc that to_owned does not deep-copy
clone_into 201 The provided method beside to_owned: refilling a buffer instead of allocating one, counted — plus the three ways it does not pay, and the backwards argument order that blocked it for five years
The comparison traits 201 == and < are traits, and the Partial half is why f64 has both while having neither Eq nor Ord — plus the derived Ord that sorts by field declaration order. Stub
Read and Write 201 The two traits between your code and every byte source there is — &[u8] is a Read, which is the whole testing story, and a BufWriter that flushes on drop throws the error away. Stub
Links and videos reference The reading behind the section

Three trait pages live outside this folder, because they are met long before anyone goes looking for a traits section: Copy vs Clone, Debug and Display, and the Default trait. They stay where they are; this section links them rather than moving them.

Trait bounds live outside it too, in Where the bound goes — because the question they answer is a question about a generic (what may this T do?) rather than about a trait, and because the page's real subject is the placement: on the impl that spends the bound, never on the struct.

Not yet written

The topics below are the rest of the map, in rough order of when you need them. They are listed here rather than as empty pages so the gaps are visible without pretending to be lessons: associated types and how they differ from generic parameters, the orphan rule and coherence in full (the everyday half — which impls you may write, and one blanket impl — is on Extension traits and From and Into), blanket impls beyond that one, negative impls, trait aliases, and async traits.

Po polsku

trait to po polsku cecha — i ta biblioteka używa tego słowa dokładnie raz, jako glosy przy pierwszym wystąpieniu, a dalej pisze konsekwentnie trait. Powód jest czysto praktyczny: słowem kluczowym jest trait, kompilator mówi the trait bound T: Display is not satisfied i wypisuje E0277, a ktoś, kto zna wyłącznie „cechę”, nie przeczyta komunikatu ani niczego nie wyszuka. Warto przy okazji wiedzieć, w którym miejscu mapy się stoi: polskie tłumaczenie Tour of Rust kończy się na rozdziale piątym, czyli dokładnie przed cechami. Od tej strony w górę polskich materiałów praktycznie nie ma i spójność słownictwa jest już na twojej głowie.

Największa pułapka dla kogoś idącego tu z Javy, C# albo ABAP-a to odruch „cecha to interfejs”. Blisko, ale nie to samo, i ta strona mówi wprost dlaczego: w Ruscie nie ma klas ani dziedziczenia. Trzy różnice widać od razu — trait może nieść domyślne implementacje metod, a nie tylko sygnatury; można go zaimplementować dla typu, którego się nie napisało, nie dotykając jego definicji (z zastrzeżeniem orphan rule, o której ta strona uczciwie pisze, że jeszcze nie ma tu swojego rozdziału); a trait Shout: Display nie jest rodzicem, tylko ograniczeniem (bound) — znaczy „kto implementuje Shout, musi też implementować Display”. Zdanie warte zapamiętania jest jednak inne: wszystko, co funkcja generyczna wie o swoim argumencie, wie dlatego, że powiedziało to ograniczenie cechy. Typy generyczne i trait to jedna maszyna, nie dwie, i uczenie się ich osobno przedłuża tylko ten etap, na którym oba wyglądają na magię.

Kilka wskazówek nawigacyjnych, bo ta strona jest spisem treści. Ograniczenia cech (trait bounds) opisano w rozdziale o typach generycznych, nie tutaj — pytanie, na które odpowiadają, brzmi „co wolno temu T?”, więc dotyczy generyka, a nie cechy. Trzy cechy spotykane najwcześniej (Copy i Clone, Debug i Display, Default) zostały w swoich pierwotnych rozdziałach i są stąd tylko podlinkowane. Pierwszy błąd, który cię tu spotka, to niemal na pewno E0599: „nie ma takiej metody”, choć metoda jest — po prostu trait nie został wciągnięty w zasięg przez use. I jedna rzecz do wyszukiwania: to, co kompilator nazywa dziś dyn compatibility, wszystkie starsze teksty — a polskie w zasadzie wszystkie — nazywają object safety. Szukaj po obu.

Szukaj po polsku: cechy w Ruscie · cecha a interfejs · rust trait not in scope E0599 · rust trait bound not satisfied E0277 · rust dyn compatibility object safety