Implementing your trait for references¶
Level: 301 · deep dive
One line: If fn show<D: Describe>(d: D) accepts a Price but not a &Price or a Box<Price>, every caller holding a reference has to move or clone — and three forwarding impls, impl<T: Describe + ?Sized> Describe for &T and its two siblings, fix that for every caller at once.
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.
What it has to cover¶
- The refusal on 1.98.0:
show(&p)isE0277, the trait bound&Price: Describeis not satisfied, and the compiler's help — consider removing the leading&-reference — moves the value the caller wanted to keep.show(Box::new(p))gets consider dereferencing here - The three forwarding impls, each calling
(**self).describe(), and why each needs?Sizedso&dyn DescribeandBox<dyn Describe>qualify too - What std already does, so callers expect it of you:
Readfor&mut RandBox<R>(a function takingR: Readby value still accepts&mut file),Iteratorfor&mut I(sofirst_two(&mut it)leavesitusable), andFnfor&F - Which impls a trait's receivers allow: with only
&selfmethods, can it forward through&T,&mut T,Box<T>,Rc<T>andArc<T>? With a&mut selfmethod, which of those drop out? With aselfmethod, any? - Why method-call tests hide the gap:
p.describe()and(&p).describe()both compile through auto-referencing and auto-deref, so only a generic call reveals the missing impl - Adding the impls in a later release: does a blanket impl for
&Tcollide with anything a downstream crate may already have written? See SemVer hazards - Rust for Rustaceans ch. 3 → "Unsurprising" → "Ergonomic Trait Implementations" as the source
The trap it exists for¶
Testing a trait only through method calls. Every test compiles because the dot operator borrows and dereferences as needed, the crate ships, and the first user with a &Price in hand and a generic function to call gets E0277 — with a compiler suggestion that moves their value away.
Where this sits¶
Blanket impls covers blanket impls in general and the coherence rules that limit them; Method resolution explains why the dot hides the gap; Read and Write is where std's forwarding impls make I/O testable. This page is only the three forwarding impls a trait author owes callers.
See also¶
- Blanket impls — one impl for every type that meets a bound, and
E0119 - Method resolution — auto-ref and auto-deref at the dot
ReadandWrite—&[u8]as a reader,&mut Ras a reader too- Step 6: one blanket impl covers every
Clonetype — a std blanket impl read line by line - Marker traits —
Sized, the bound?Sizedrelaxes - Generic or concrete parameters — the generic function these impls exist for
- Rust API Guidelines — C-RW-VALUE ↗ — why a reader is taken by value, which only works because of
impl Read for &mut R
If you are coming from another language¶
- C++. A function taking
const Describable&binds to any lvalue of a matching type, with no extra declarations. In Rust&Priceis a distinct type fromPrice, and a trait bound sees the difference until an impl bridges it. - Go. The method set of
*Tincludes the methods declared onT, so a pointer satisfies every interface its value does, automatically. Rust has no such rule for trait bounds; the forwarding impl is the rule, written by hand once per trait. - Java. Every object variable is already a reference, so the question never comes up — which is also why Java code can never say "this function takes ownership".
Po polsku¶
Jeśli funkcja generyczna fn show<D: Describe>(d: D) przyjmuje Price, ale nie &Price ani Box<Price>, każdy, kto trzyma referencję, musi przenieść albo sklonować wartość — a podpowiedź kompilatora („usuń &”) prowadzi właśnie do przeniesienia. Rozwiązaniem są trzy implementacje przekazujące (forwarding impls) dla &T, &mut T i Box<T> z ?Sized, tak jak robi to biblioteka standardowa dla Read i Iterator. Testy wywołujące tylko metody tego nie wykryją, bo operator kropki sam dokłada i zdejmuje referencje.
Szukaj po polsku: implementacja cechy dla referencji · implementacja ogólna (blanket impl) · rust impl trait for &T · rust ergonomic trait implementations · rust forwarding impl box dyn