In Rust, Clone
is a trait that specifies the clone
method (and clone_from
). Some traits, like StrSlice
and CloneableVector
specify a to_owned
fn. Why would an implementation need both? What is the difference?
I did an experiment with Rust strings, which have both methods, and it demonstrates that there is a difference, but I don't understand it:
fn main() { test_clone(); test_to_owned(); } // compiles and runs fine 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); // prints true println!("{:?}", c2 == s2); // prints true } 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); // compile-time error here (see below) println!("{:?}", c2 == s2); }
The compile time error for the to_owned
example is:
error: mismatched types: expected `~str` but found `&'static str` (str storage differs: expected `~` but found `&'static `) clone.rs:30 println!("{:?}", c1 == s1);
Why would the first example work but not the second?
The ToOwned trait generalizes Clone to construct owned data from any borrow of a given type.
Differs from Copy in that Copy is implicit and extremely inexpensive, while Clone is always explicit and may or may not be expensive. In order to enforce these characteristics, Rust does not allow you to reimplement Copy , but you may reimplement Clone and run arbitrary code.
For this reason, String is Clone but not Copy . Clone is a supertrait of Copy , so everything which is Copy must also implement Clone . If a type is Copy then its Clone implementation only needs to return *self (see the example above).
The only correct way to copy a String is to allocate a new block of heap memory to copy all the characters into, which is what String 's Clone implementation does. https://doc.rust-lang.org/book/second-edition/ch04-01-what-is-ownership.html covers these topics in much more detail.
.clone()
returns its receiver. clone()
on a &str
returns a &str
. If you want a String
, you need a different method, which in this case is .to_owned()
.
For most types, clone()
is sufficient because it's only defined on the underlying type and not on the reference type. But for str
and [T]
, clone()
is implemented on the reference type (&str
and &[T]
), and therefore it has the wrong type. It's also implemented on the owned types (String
and Vec<T>
), and in that case clone()
will return another owned value.
Your first example works because c1
and s1
(and c2
and s2
) have the same types. Your second example fails because they don't (c1
is String
whereas s1
is &str
). That's a perfect example of why the separate methods are necessary.
As of current Rust, both now compile, but in test_clone()
c1
is a String
and in test_to_owned()
it's a &str
. I'm pretty sure it compiles as Rust is now more lenient about automatically referencing and dereferencing values. In this particular example I believe the c1 == s1
line is compiled as though it said &*c1 == s1
. If you wish to prove the types involved you can add a deliberate type error, such as let _: i32 = c1;
and the error message will show the type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With