Skip to content

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

impl<T: Clone> ToOwned for T {
    type Owned = T;
    fn to_owned(&self) -> T {
        self.clone()
    }
}

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():

  1. First candidate, &Ticket. A to_owned with that receiver type would be Ticket's, from the blanket impl — but its bound Ticket: Clone fails.
  2. Second candidate, &&Ticket. &Ticket is Clone (step 4), so the blanket impl covers it, with Owned = &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() reaches str's impl and gives a String. Step 5's search matches it at the first candidate, because its receiver type is &str — exactly the type of s, with nothing added or removed.
  • <str as ToOwned>::to_owned(s) names Self = str outright, and gives the same String.
  • ToOwned::to_owned(&s) passes a &&str, which makes Self = &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 the Cow built on it.
  • Step 8: Rc and Cow are Clone, 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 "ToOwned allocates" is not a rule.
  • Three ToOwned katas, 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:

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