web-dev-qa-db-ja.com

Rustで、clone()とto_owned()の違いは何ですか?

Rustでは、Clonecloneメソッド(および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);

なぜ最初の例は機能するが2番目の例は機能しないのですか?

38
quux00

.clone()はそのレシーバーを返します。 _&str_に対するclone()は、_&str_を返します。 Stringが必要な場合は、別のメソッドが必要です。この場合は.to_owned()です。

ほとんどのタイプでは、clone()で十分です。これは、基礎となるタイプでのみ定義され、参照タイプでは定義されないためです。ただし、strおよび_[T]_の場合、clone()は参照型(_&str_および_&[T]_)に実装されているため、型が間違っています。また、所有される型(Stringおよび_Vec<T>_)にも実装されており、その場合、clone()は別の所有される値を返します。

_c1_および_s1_(および_c2_および_s2_)が同じ型であるため、最初の例が機能します。 2番目の例は失敗しないため失敗します(_c1_はStringですが、_s1_は_&str_)。これは、個別のメソッドが必要な理由の完璧な例です。


現在のRustでは、両方ともコンパイルされていますが、test_clone()では_c1_はStringであり、test_to_owned()では_&str_です。 Rustは値の自動参照と逆参照についてより寛大になりました。この特定の例では、_c1 == s1_行が_&*c1 == s1_。関連する型を証明したい場合は、_let _: i32 = c1;_などの意図的な型エラーを追加すると、エラーメッセージに型が表示されます。

34
Lily Ballard