Question
In Rust, what is the difference between clone() and to_owned()?
Clone is a trait that provides the clone method (and clone_from). Some types and traits, such as string slices and collection-related abstractions, also provide a to_owned() method. Why would a type need both methods, and how do they differ?
Consider this Rust example:
fn main() {
test_clone();
test_to_owned();
}
fn test_clone() {
let s1: &'static str = "I am static";
let s2 = "I am boxed and owned".to_string();
let c1 = s1.clone();
let c2 = s2.clone();
println!("{:?}", c1);
println!("{:?}", c2);
println!("{:?}", c1 == s1);
println!("{:?}", c2 == s2);
}
fn test_to_owned() {
let s1: &'static str = "I am static";
let s2 = "I am boxed and owned".to_string();
let c1 = s1.to_owned();
let c2 = s2.to_owned();
println!("{:?}", c1);
println!("{:?}", c2);
println!("{:?}", c1 == s1); // Why does this fail to compile?
println!("{:?}", c2 == s2);
}
The key confusion is this: clone() works for both values, but to_owned() changes the behavior for &str. Why does the first example compile while the second produces a type mismatch?
Short Answer
By the end of this page, you will understand that clone() duplicates a value without changing its type, while to_owned() converts borrowed data into its owned version. In Rust, this difference matters most for types like &str, where clone() returns another &str, but to_owned() returns a String.
Concept
clone() and to_owned() are related, but they solve different problems.
clone()
clone() comes from the Clone trait.
Its job is simple:
- make a duplicate of a value
- keep the same type
Examples:
- cloning a
Stringgives anotherString - cloning a
Vec<T>gives anotherVec<T> - cloning a
&strgives another&str
That last one is important: a string slice &str is a borrowed reference, not an owned string buffer. Cloning it does not allocate new string storage. It just copies the reference.
to_owned()
to_owned() is about converting data into an owned form.
Its job is:
- if you have borrowed data, create an owned version of it
- if you already have owned data, it often behaves like a clone
Examples:
&str.to_owned()produces aString&[T].to_owned()produces aVec<T>String.to_owned()produces aString
So the big idea is:
clone()= duplicate this value as the same typeto_owned()= give me an owned version of this value
Why both exist
Rust distinguishes very clearly between:
- borrowed data n- owned data
Many APIs work with borrowed data because borrowing is cheaper and more flexible. But sometimes you need to store data beyond the lifetime of the borrow, return it, or modify it independently. That is when to_owned() is useful.
clone() does not solve that conversion problem. It only duplicates the current type.
Why this matters
This distinction appears everywhere in Rust:
&strvsString&[T]vsVec<T>- borrowed config values vs stored application state
- temporary input vs owned output
Understanding the difference helps you reason about ownership, allocations, performance, and API design.
Mental Model
Think of borrowed and owned data like reading a book.
- A borrowed value is like borrowing a library book.
- An owned value is like buying your own copy.
Now compare the methods:
-
clone()means: make another copy of whatever you currently have.- If you currently have a library card pointing to a book (
&str), cloning just copies the card. - You still do not own the book.
- If you currently have a library card pointing to a book (
-
to_owned()means: get your own personal copy.- If you borrowed the book (
&str),to_owned()buys a copy (String). - If you already owned the book (
String), it can make another owned copy.
- If you borrowed the book (
So for &str:
clone()-> another borrowed&strto_owned()-> an ownedString
That is why the types differ.
Syntax and Examples
Core syntax
let a = value.clone();
let b = value.to_owned();
The important question is: what type is value?
Example 1: &str
fn main() {
let s: &str = "hello";
let a = s.clone();
let b = s.to_owned();
// a: &str
// b: String
println!("{}", a);
println!("{}", b);
}
Explanation:
s.clone()returns another&strs.to_owned()returns aString
Example 2: String
fn main() {
let s = String::from("hello");
let a = s.clone();
let b = s.to_owned();
// a: String
// b: String
println!("{}", a);
println!("{}", b);
}
For String, both methods produce a new owned String.
Example 3: Slice to vector
fn main() {
let nums: &[i32] = &[1, 2, 3];
let a = nums.clone();
let b = nums.to_owned();
// a: &[i32]
// b: Vec<i32>
println!("{:?}", a);
println!("{:?}", b);
}
Again:
clone()keeps the same type:&[i32]to_owned()produces the owned version:Vec<i32>
Your original string comparison issue
fn main() {
let s1: &str = "I am static";
let c1 = s1.clone(); // &str
let c2 = s1.to_owned(); // String
println!("{}", c1 == s1); // OK: &str == &str
println!("{}", c2 == s1); // Often works in modern Rust due to trait impls
}
Conceptually, the reason for the old error is that c2 and s1 were different types:
c2: owned strings1: borrowed string slice
The important lesson is not the historical compiler behavior, but that to_owned() changes &str into String, while clone() does not.
Step by Step Execution
Consider this small example:
fn main() {
let s: &str = "rust";
let a = s.clone();
let b = s.to_owned();
println!("{}", a);
println!("{}", b);
}
Step by step
1. Create s
let s: &str = "rust";
sis a string slice- it points to string data
- it does not own that data
2. Clone s
let a = s.clone();
clone()preserves the typeais also&str- Rust copies the reference, not the string contents
So now:
spoints to the string dataapoints to the same string data
3. Convert to owned
let b = s.to_owned();
to_owned()creates an owned versionbis aString- Rust allocates memory for a new string buffer and copies the text into it
So now:
sis borrowed&strais borrowed&strbis ownedString
4. Print values
println!("{}", a);
println!("{}", b);
Both print rust, but the ownership is different.
Type trace
| Variable | Value | Type |
|---|---|---|
s | "rust" | &str |
a | "rust" | &str |
b | "rust" | String |
That type difference explains the behavior in your original example.
Real World Use Cases
When to use clone()
Use clone() when you want another value of the same type.
Common examples:
- duplicate a
Stringyou already own - copy a
Vec<T>before modifying one version - duplicate configuration data stored in an owned struct
- copy an
Arc<T>orRc<T>handle
let name = String::from("Alice");
let backup = name.clone();
When to use to_owned()
Use to_owned() when you have borrowed data but need to own it.
Common examples:
- convert
&strinput intoStringfor storage - convert a slice
&[T]intoVec<T> - take borrowed request data and keep it after the request ends
- build structs that own their fields
fn save_username(input: &str) -> String {
input.to_owned()
}
In APIs and parsing
A function may accept &str because that is flexible:
fn parse_name(input: &str) {
// use borrowed data
}
But if the function needs to store the value, it often converts it:
struct User {
name: String,
}
fn build_user(input: &str) -> User {
User {
name: input.to_owned(),
}
}
That is a very common Rust pattern.
Real Codebase Usage
In real projects, developers often use these methods as part of broader ownership patterns.
Pattern: accept borrowed, store owned
This is one of the most common Rust API designs.
struct Config {
host: String,
}
impl Config {
fn new(host: &str) -> Self {
Self {
host: host.to_owned(),
}
}
}
Why this is good:
- callers can pass
&stror string literals easily - the struct owns its data safely
Pattern: clone owned state before mutation
let original = String::from("draft");
let editable = original.clone();
Used when:
- you need a backup
- you want to preserve the original value
- ownership rules prevent moving the original
Pattern: guard clauses with borrowed input
fn normalize_name(input: &str) -> Option<String> {
if input.trim().is_empty() {
return None;
}
Some(input.trim().to_owned())
}
This combines:
- validation
- borrowing for efficiency
to_owned()only when needed
Pattern: slices to owned collections
fn copy_chunk(data: &[u8]) -> Vec<u8> {
data.to_owned()
}
This is common in:
- networking
- file processing
- parsers
- binary protocols
Performance note
Developers avoid unnecessary allocation when possible:
- use borrowed types in function parameters
- call
to_owned()only when ownership is required - use
clone()only when duplicating owned data intentionally
That makes code both ergonomic and efficient.
Common Mistakes
1. Assuming clone() always makes a deep owned copy
Broken assumption:
let s: &str = "hello";
let c = s.clone();
Many beginners expect c to be a String. It is not.
sis&strcis also&str
Fix
Use to_owned() or to_string() when you need ownership.
let s: &str = "hello";
let owned = s.to_owned(); // String
2. Forgetting that to_owned() may change the type
Broken example:
let s: &str = "hello";
let x = s.to_owned();
// x is String, not &str
Fix
Check the resulting type mentally:
&str -> String&[T] -> Vec<T>
3. Using clone() just to satisfy the borrow checker
Beginners sometimes write too many clones:
let a = some_string.clone();
let b = a.clone();
let c = b.clone();
Fix
Ask:
- Do I need another owned value?
- Can I borrow instead?
- Can I restructure the code?
Cloning is valid, but unnecessary cloning can waste memory and CPU.
4. Confusing equality with identical types
In older Rust versions, comparing String and &str could fail depending on trait implementations.
let s: &str = "hello";
let owned = s.to_owned();
The conceptual issue is that these are different types even if they contain the same text.
Fix
Know the types involved. If needed, compare compatible forms:
let s: &str = "hello";
let owned = s.to_owned();
println!("{}", owned == s);
Or explicitly borrow:
println!("{}", owned.as_str() == s);
5. Using to_owned() where borrowing is enough
fn print_name(name: &str) {
let owned = name.to_owned(); // unnecessary if only printing
println!("{}", owned);
}
Fix
Only allocate when you need ownership.
fn print_name(name: &str) {
println!("{}", name);
}
Comparisons
| Method | Main purpose | Keeps same type? | Can convert borrowed to owned? | Example on &str | Example on String |
|---|---|---|---|---|---|
clone() | Duplicate a value | Yes | No | &str -> &str | String -> String |
to_owned() | Produce an owned version | Not always | Yes | &str -> String | String -> String |
to_string() | Convert to String | No | Often yes for displayable types | &str -> String | String -> String |
clone() vs to_owned()
- Use
clone()when you want the same type again. - Use
to_owned()when you want ownership.
to_owned() vs to_string()
For strings, these often look similar:
let a = "hello".to_owned();
let b = "hello".to_string();
Both produce a String here.
But conceptually:
to_owned()means “make the owned form of this borrowed value”to_string()means “convert this value into aStringrepresentation”
to_owned() is more directly about ownership. to_string() is more general string conversion.
Borrowed vs owned forms
| Borrowed | Owned |
|---|---|
&str | String |
&[T] | Vec<T> |
&Path | PathBuf |
&OsStr | OsString |
to_owned() is especially useful across these pairs.
Cheat Sheet
Quick rules
clone()returns the same type.to_owned()returns an owned version.- For borrowed data,
to_owned()often allocates. - For already owned data,
to_owned()often behaves similarly toclone().
Common examples
let s: &str = "abc";
let a = s.clone(); // &str
let b = s.to_owned(); // String
let s = String::from("abc");
let a = s.clone(); // String
let b = s.to_owned(); // String
let slice: &[i32] = &[1, 2, 3];
let a = slice.clone(); // &[i32]
let b = slice.to_owned(); // Vec<i32>
When to choose which
- Need the same type? Use
clone(). - Need ownership from borrowed data? Use
to_owned(). - Need a
Stringtext representation? Considerto_string().
Important edge case
For &str:
clone()does not create aStringto_owned()does create aString
Memory behavior
- Cloning a reference like
&stris cheap: it copies the pointer and length. to_owned()on&strcopies the actual text into new owned memory.
FAQ
Why does clone() on &str not create a String?
Because clone() preserves the original type. A &str cloned value is still a &str.
Is to_owned() the same as clone() for String?
In practice, both produce a new String. The conceptual difference is that to_owned() means “give me an owned version,” while clone() means “duplicate this exact type.”
Should I use to_owned() or to_string() for &str?
Both can produce a String. For borrowed-to-owned conversion, to_owned() communicates intent more clearly.
Does to_owned() always allocate memory?
Not always in every possible type, but for common borrowed types like &str and slices, it creates owned data and therefore allocates.
Why did the comparison fail in the original example?
Because c1 from to_owned() became an owned string type, while s1 was still a borrowed string slice. The values may have the same text, but the types are different.
When should I avoid clone()?
Avoid it when borrowing is enough. Cloning owned data can be unnecessary work if you do not need an independent copy.
Mini Project
Description
Build a small Rust program that accepts borrowed text and stores it inside an owned struct. This demonstrates why to_owned() exists and how it differs from clone() on borrowed string slices.
Goal
Create a User struct that stores a name as String, and write functions that show the difference between copying a borrowed &str and converting it into owned data.
Requirements
- Define a
Userstruct with aname: Stringfield. - Write one function that uses
clone()on a&strand prints the result type behavior. - Write another function that uses
to_owned()on a&strand stores it in aUser. - Show that a
Stringcan be duplicated with eitherclone()orto_owned(). - Print enough output to verify the differences clearly.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.