2017-07-15 20 views
3

背景爲什麼不實現字符串從<&String>?

我知道,在魯斯特人喜歡&str而非&String。但在某些情況下,我們只給予&String

一個例子是當你撥打std::iter::Iterator::peekable。返回值是一個Peekable<I>對象,它將原始迭代器封裝到它中,併爲您提供一個額外的方法peek

這裏的關鍵是peek只給你一個迭代器項的引用。所以如果你有一個包含String的迭代器,在這種情況下你只有&String。因爲,你可以很容易地使用as_str得到一個&str,但在我將在下面顯示的代碼相當於撥打clone

問題

此代碼

#[derive(Debug)] 
struct MyStruct(String); 

impl MyStruct { 
    fn new<T>(t: T) -> MyStruct 
    where 
     T: Into<String>, 
    { 
     MyStruct(t.into()) 
    } 
} 

fn main() { 
    let s: String = "Hello world!".into(); 
    let st: MyStruct = MyStruct::new(&s); 
    println!("{:?}", st); 
} 

不編譯,因爲String沒有實現From<&String>。這不直觀。

爲什麼這不起作用?它只是標準庫的一個缺失功能​​,還有一些其他原因會阻止標準庫實現它?

在真實的代碼中,我只有一個參考String,我知道使它工作,我只需要撥打clone來代替,但我想知道爲什麼。

+2

我不會說這是反直覺的 - 其它對象不做,要麼,例如'Vec '不'impl來自<&Vec>';也'impl <'a>從<&'a str>'是一個更可能的用例,它很容易獲得。 – ljedrz

+0

我覺得真正的答案與我的相關問題有關https://stackoverflow.com/questions/45126120/if-intostring-not-implemented-for-string-why-these-implementations-are-co –

回答

4

解決您的問題,我們可以想象加入新通用IMPL的標準庫:

impl<'a, T: Clone> From<&'a T> for T { ... } 

或者使其更通用:

impl<B, O> From<B> for O where B: ToOwned<Owned=O> { ... } 

不過,也有這樣做有兩個問題:

  1. 專業化:允許重疊特質 - impls的特化功能仍然不穩定。事實證明,以合理的方式設計專業化的方式是more difficult than expected(主要是由於生命期)。

    如果沒有穩定性,Rust開發人員會非常小心,不要在標準庫的公共API中的某處公開該功能。這並不意味着它根本不用於std!一個着名的例子是str的專用ToString impl。它被引入in this PR。正如你可以在PR的討論中看到的,他們只接受它,因爲它不會改變API(to_string()已經爲str實施)。

    但是,當我們添加上面的通用impl時會有所不同:它會更改API。因此,它在std中是不允許的。

  2. coreVS std:性狀FromInto都在 core library定義的,而CloneToOwnedstd中定義。這意味着我們不能在core中添加通用impl,因爲core不知道std的任何內容。但是我們也不能在std中添加泛型impl,因爲泛型impls需要與特徵放在同一個箱子中(這是孤兒規則的結果)。因此,在添加這樣的通用impl之前,它需要某種形式的重構和移動定義(這可能會也可能不困難)。


注意添加

impl<'a> From<&'a String> for String { ... } 

...工作得很好。它不需要專業化,並且沒有孤兒規則的問題。但是當然,當通用impl有意義時,我們不想添加特定的impl。

感謝可愛的人在IRC的向我解釋東西)

相關問題