简体   繁体   中英

In Rust, what is the difference between clone() and to_owned()?

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?

.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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM