Step 6: One blanket impl covers every Clone type — references included¶
How to learn ToOwned › Step 6 of 10 · back: Step 5 — The dot takes the first receiver that fits · next: Step 7 — Borrow is the way back
Level: 201 · a step on a learning path
One line: impl<T: Clone> ToOwned for T gives to_owned() to every Clone type, doing exactly clone(). Steps 4 and 5 meet here: every &T is Clone, so when Foo is not Clone, foo_ref.to_owned() finds nothing on Foo, finds the impl for &Foo instead, and hands back the pointer.
The impl¶
A blanket impl implements a trait for every type that meets a bound, including types written after it. This one means nobody wrote impl ToOwned for i32, or for String, or for your #[derive(Clone)] struct — they all have to_owned(), it is clone() under another name, and Owned is the type itself.
So std's own impls fall in two groups, and step 1's table is the split: the hand-written ones, all on unsized types, and this one, covering everything that is Clone.
Steps 4 and 5 meet here¶
Take a: &Ticket, where Ticket is not Clone, and call a.to_owned():
- First candidate,
&Ticket. Ato_ownedwith that receiver type would beTicket's, from the blanket impl — but its boundTicket: Clonefails. - Second candidate,
&&Ticket.&TicketisClone(step 4), so the blanket impl covers it, withOwned = &Ticket— match.
You get the same address back. Annotate the result as let t: Ticket = a.to_owned(); and the compiler says E0308, expected Ticket, found &Ticket, with not a word about Clone. Add #[derive(Clone)] and step 1 matches instead: a new value, at a new address. The checkpoint shows both.
One &str, two impls¶
&str is Clone (step 4), so this blanket impl covers it too, with Owned = &str. There is no hand-written impl ToOwned for &str — this is the only one — but it means a &str can reach two ToOwned impls: str's, written by hand, and &str's, from the blanket. Which one a call lands on depends on how the call is spelled:
s.to_owned()reachesstr's impl and gives aString. Step 5's search matches it at the first candidate, because its receiver type is&str— exactly the type ofs, with nothing added or removed.<str as ToOwned>::to_owned(s)namesSelf = stroutright, and gives the sameString.ToOwned::to_owned(&s)passes a&&str, which makesSelf = &str, and gives back a&str.
The two impls are not a collision. Coherence forbids two impls for the same Self, and str and &str are as different as i32 and &i32. Both exist; the call decides.
Why it also blocks your own impl¶
The blanket impl already covers every Clone type, so impl ToOwned for MyType on a Clone type is a second, conflicting impl: E0119. Coherence allows one impl per type per trait. Step 10 is what to do instead.
Nor would specialization let you override it. On nightly, with #![feature(specialization)], impl ToOwned for Mine on a Clone type is still refused, now as E0520: "Owned specializes an item from a parent impl, but that item is not marked default" (rustc 1.100.0-nightly, 2026-08-27). The blanket impl's items are final on purpose, and generic code leans on it: fn f<T: Clone>(x: &T) -> T { x.to_owned() } compiles only because Owned = T is guaranteed. Copy the trait, mark the blanket's type Owned = T as default, and that same function is E0308 — once the owned type could be something else, no generic caller may assume it is T.
Checkpoint¶
Predict before you open the answer. What is 42_i32.to_owned()? For a Ticket that is not Clone, is (&ticket).to_owned() a new ticket or the same address? And for s: &str, what do s.to_owned() and ToOwned::to_owned(&s) return?
The answer
Verified output of the_blanket_to_owned.rs — regenerated by tools/run_examples.py, never hand-typed.
For a Clone type, Owned is the type itself
<i32 as ToOwned>::Owned = i32
<String as ToOwned>::Owned = alloc::string::String
<Vec<u8> as ToOwned>::Owned = alloc::vec::Vec<u8>
Checkpoint. What is 42_i32.to_owned()? Is (&ticket).to_owned() a new ticket?
42_i32.to_owned() -> i32 42
a.to_owned() is the same address as a: true (it is a &Ticket, seat 12)
Derive Clone, and the same call on the same kind of reference copies the value
b.to_owned() is the same address as b: false (it is a Seat, seat 12)
One &str, two impls: the spelling of the call picks one
<str as ToOwned>::Owned = alloc::string::String
<&str as ToOwned>::Owned = &str (the blanket impl: &str is Clone)
s.to_owned() Self = str -> alloc::string::String
<str as ToOwned>::to_owned(s) Self = str -> alloc::string::String
ToOwned::to_owned(&s) Self = &str -> &str
Practice¶
Own every borrow in a &[&T]. Write clone_each<T: ?Sized + ToOwned>(xs: &[&T]) -> Vec<T::Owned>, and start with the body everybody writes first: xs.iter().map(|x| x.to_owned()).collect(). Before you compile it, say what x is, which impl the dot lands on, and whether the result is an error or a quietly wrong Vec. Then make the same closure quiet: collect ["ada", "grace"] into a Vec<_> and name the element type you get.
Fix the body three ways: dereference inside the closure, let the closure's pattern do the dereference, and take the dot out of it by passing T::to_owned as a path. One of the three will not compile until you add one more adapter. Call each with a &str, a &[i32], a &Path and a plain &i32, and say why the last is allowed at all.
Solution
the_blanket_to_owned_kata.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
//! Kata solution for step 6: own every borrow in a `&[&T]`. The obvious
//! closure lands on the blanket impl for `&T` — a hard error where the return
//! type asks for `T::Owned`, and a quiet `Vec<&T>` where nothing asks.
//!
//! rustc --edition 2024 the_blanket_to_owned_kata.rs -o /tmp/tbtok && /tmp/tbtok
use std::any::type_name_of_val;
use std::path::Path;
// Written as `xs.iter().map(|x| x.to_owned()).collect()` this is E0277:
// `x` is a `&&T`, the dot matches the blanket impl for `&T` first, and a
// `Vec<T::Owned>` cannot be built from an iterator over `&T`.
/// Dereference to the rung you want: `*x` is a `&T`, so `Self = T`.
fn by_deref<T: ?Sized + ToOwned>(xs: &[&T]) -> Vec<T::Owned> {
xs.iter().map(|x| (*x).to_owned()).collect()
}
/// Let the pattern do the dereference: `|&x|` binds `x: &T`.
fn by_pattern<T: ?Sized + ToOwned>(xs: &[&T]) -> Vec<T::Owned> {
xs.iter().map(|&x| x.to_owned()).collect()
}
/// No dot, so no search: `T::to_owned` takes a `&T`, and `copied` yields one.
fn by_path<T: ?Sized + ToOwned>(xs: &[&T]) -> Vec<T::Owned> {
xs.iter().copied().map(T::to_owned).collect()
}
fn main() {
println!("1. Where nothing asks for T::Owned, the obvious closure is quiet");
let words: [&str; 2] = ["ada", "grace"];
let quiet: Vec<_> = words.iter().map(|x| x.to_owned()).collect();
println!(" words.iter().map(|x| x.to_owned()) -> {}", type_name_of_val(&quiet));
println!();
println!("2. Three bodies that reach T's impl, four kinds of T");
let slices: [&[i32]; 2] = [&[1, 2], &[3]];
let paths = [Path::new("/a"), Path::new("/b/c")];
let numbers = [&1, &2];
println!(" T = str by_deref -> {:<16} {}", format!("{:?}", by_deref(&words)), type_name_of_val(&by_deref(&words)));
println!(" T = [i32] by_pattern -> {:<16} {}", format!("{:?}", by_pattern(&slices)), type_name_of_val(&by_pattern(&slices)));
println!(" T = Path by_path -> {:<16} {}", format!("{:?}", by_path(&paths)), type_name_of_val(&by_path(&paths)));
println!(" T = i32 by_deref -> {:<16} {}", format!("{:?}", by_deref(&numbers)), type_name_of_val(&by_deref(&numbers)));
println!();
println!("3. Why i32 works too: the blanket impl gives every Clone type Owned = Self");
println!(" <i32 as ToOwned>::Owned is i32, so Vec<T::Owned> is Vec<i32>");
}
Verified output of the_blanket_to_owned_kata.rs — regenerated by tools/run_examples.py, never hand-typed.
1. Where nothing asks for T::Owned, the obvious closure is quiet
words.iter().map(|x| x.to_owned()) -> alloc::vec::Vec<&str>
2. Three bodies that reach T's impl, four kinds of T
T = str by_deref -> ["ada", "grace"] alloc::vec::Vec<alloc::string::String>
T = [i32] by_pattern -> [[1, 2], [3]] alloc::vec::Vec<alloc::vec::Vec<i32>>
T = Path by_path -> ["/a", "/b/c"] alloc::vec::Vec<std::path::PathBuf>
T = i32 by_deref -> [1, 2] alloc::vec::Vec<i32>
3. Why i32 works too: the blanket impl gives every Clone type Owned = Self
<i32 as ToOwned>::Owned is i32, so Vec<T::Owned> is Vec<i32>
x is a &&T, so the first candidate is &T's to_owned, from this page's blanket impl. That candidate returns &T. Inside clone_each the return type asks for T::Owned, so rustc 1.98.0 refuses with E0277: "a value of type Vec<<T as std::borrow::ToOwned>::Owned> cannot be built from an iterator over elements of type &T". In a Vec<_> nothing asks, and you get a Vec<&str> with no warning. .map(T::to_owned) on its own is E0631, because map passes a &&T and a function path gets no deref coercion. .copied() supplies the &T. And &i32 works because ?Sized allows an unsized T without requiring one.
This kata is one of three ToOwned katas, run, which also covers a wrong word in the version that circulates.
What this step sets up¶
- Step 7: the bound on
type Owned, and theCowbuilt on it. - Step 8:
RcandCowareClone, so the blanket impl is what.to_owned()reaches on them. - Step 10:
E0119, and the inherent method that sidesteps it. - After the steps:
42_i32.to_owned()touches no heap — one reason "ToOwnedallocates" is not a rule. - Three
ToOwnedkatas, run: the kata above as it circulates, plus two more, each claim checked.
Go deeper¶
Read: Extension traits — one impl, every iterator for a blanket impl reaching types it has never seen, and the rule that permits it. Then ToOwned — the trap that blanket impl sets, which has the E0308 run.
Around it in the library:
ToOwned— the trap in generic code- Reading the
ToOwneddocs — 8. Implementors, where the blanket impl is one row among the others - "No method named …", the blanket impl whose bound your type misses
- Where the bound goes, bounds on an
impl FromandInto, the other famous blanket impl:impl<T, U: From<T>> Into<U> for T
Docs: ToOwned's implementors ↗, where the blanket row is impl<T> ToOwned for T where T: Clone · Generic implementations ↗ · Trait implementation coherence ↗, both in the Reference
Words: orphan rule in the glossary.
Katas: Own every borrow in a &[&T] — the obvious closure, loud in one place and quiet in another, fixed three ways. Then give every slice a .middle() — one trait, two methods, and only one of them reachable through a dot. Then predict the owned twin before you run it — six receivers, and the two everybody gets wrong.
Po polsku¶
impl<T: Clone> ToOwned for T to implementacja zbiorcza (blanket impl): każdy typ Clone dostaje to_owned(), które robi dokładnie clone(), a Owned to ten sam typ. Nikt nie napisał impl ToOwned for i32 — i nie musiał.
Tu spotykają się kroki 4 i 5. Każde &T jest Clone, więc dla a: &Ticket, gdy Ticket nie jest Clone, wyszukiwanie mija Ticket i trafia na implementację dla &Ticket: dostajesz kopię wskaźnika. Z adnotacją typu kompilator zgłasza E0308 bez słowa o Clone. Ta sama implementacja zbiorcza sprawia, że własne impl ToOwned dla typu Clone to E0119.
Szukaj po polsku: implementacja zbiorcza · rust blanket impl ToOwned · rust to_owned returns reference
How to learn ToOwned › Step 6 of 10 · back: Step 5 · next: Step 7 — Borrow is the way back