2017-07-17 118 views
9

當與特點編寫代碼,你可以把性狀的必然性狀:<T: Trait> Box <T>和&Trait/Box <Trait>有什麼區別?

use std::fmt::Debug; 

fn myfunction1<T: Debug>(v: Box<T>) { 
    println!("{:?}", v); 
} 

fn myfunction2<T: Debug>(v: &T) { 
    println!("{:?}", v); 
} 

fn main() { 
    myfunction1(Box::new(5)); 
    myfunction2(&5); 
} 
Box或引用類型

或者直接:

use std::fmt::Debug; 

fn myfunction3(v: Box<Debug>) { 
    println!("{:?}", v); 
} 

fn myfunction4(v: &Debug) { 
    println!("{:?}", v); 
} 

fn main() { 
    myfunction3(Box::new(5)); 
    myfunction4(&5); 
} 

這些給相同的輸出。那麼區別是什麼呢?

(對此問題予以another question靈感哪裏,這只是幾個混雜的概念之一)

回答

9

與正在使用綁定的性狀來告訴你想要一個Box某種類型T實例的編譯器<T: Trait> Box<T>這執行Trait,並且您將在使用時指定T。 Rust編譯器可能會爲您的代碼中的每個不同的T創建不同的高效代碼(單態化)。

隨着Box<Trait>你告訴你想與性狀對象的指針,它實現Trait,這意味着編譯器將使用動態分配的未知類型Box編譯器。

我已經包括兩個例子,這使得差的有點清晰:

<T: Trait> Box<T>,即性狀約束:

use std::fmt::Debug; 

struct Wrapper<T> { 
    contents: Option<Box<T>>, 
} 

impl<T: Debug> Wrapper<T> { 
    fn new() -> Wrapper<T> { 
     Wrapper { contents: None } 
    } 

    fn insert(&mut self, val: Box<T>) { 
    } 
} 

fn main() { 
    let mut w = Wrapper::new(); 

    // makes T for w be an integer type, e.g. Box<i64> 
    w.insert(Box::new(5)); 

    // type error, &str is not an integer type 
    // w.insert(Box::new("hello")); 
} 

Box<Trait>,即性狀對象:

use std::fmt::Debug; 

struct Wrapper { 
    contents: Option<Box<Debug>>, 
} 

impl Wrapper { 
    fn new() -> Wrapper { 
     Wrapper { contents: None } 
    } 

    fn insert(&mut self, val: Box<Debug>) { 
    } 
} 

fn main() { 
    let mut w = Wrapper::new(); 
    w.insert(Box::new(5)); 
    w.insert(Box::new("hello")); 
} 

爲了進一步有關特質邊界與特質對象之間差異的詳細信息,我建議the section on trait objects in the first edition of the Rust book

2

重要的是,你不已經把泛型類型的引用(如&Box)的後面,你可以直接接受它:

fn myfunction3<T: Debug>(v: T) { 
    println!("{:?}", v); 
} 

fn main() { 
    myfunction3(5); 
} 

這有monomorphization同樣的好處,而不額外內存分配的缺點(Box)或需要保留某個值的所有權(&)。

我會說仿製藥應該是默認選擇 - 當動態分配/異質性時,您只需要特質對象

相關問題