在 Rust 中,clone()和 to_own()之间的区别是什么?

在 Rust 中,Clone是指定 clone方法(和 clone_from)的特性。一些特性,如 StrSliceCloneableVector指定 to_owned fn。为什么一个实现需要两者?有什么区别吗?

我用 Rust 字符串做了一个实验,两种方法都有,它证明了两者之间的区别,但我不明白:

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);
}

to_owned示例的编译时错误是:

error: mismatched types: expected `~str` but found `&'static str`
(str storage differs: expected `~` but found `&'static `)
clone.rs:30     println!("{:?}", c1 == s1);

为什么第一个例子可行,而第二个不行呢?

37572 次浏览

.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 &str and in test_to_owned() it's a String. 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.