2015-11-19 22 views
0

我想創建一個結構具有BufWriter,使用Write特質,以便此結構可以有一個緩衝作家,可以是任何實現該特質: File,Stream等。但我在我的函數有一個問題,創建結構說,我有mismatched types。以下是一個具有相同問題的示例代碼。用字段的通用特徵創建結構。預期的結構<trait>找到結構<類型,實現所說的特質>

use std::fs::File; 
use std::io::{BufWriter, Write}; 

pub struct BufWriterStruct<W: Write> { 
    pub writer: Option<BufWriter<W>>, 
} 

impl <W: Write>BufWriterStruct<W> { 
    pub fn new(filename: &str) -> BufWriterStruct<W> { 
     BufWriterStruct { 
      writer: Some(BufWriter::new(File::create(filename).unwrap())), 
     } 
    } 
} 

fn main() { 
    let tmp = BufWriterStruct::new("tmp.txt"); 
} 

Playground

與錯誤

error: mismatched types: 
expected `BufWriterStruct<W>`, 
    found `BufWriterStruct<std::fs::File>` 

相反,如果我改變我的new功能,而不是採取一個實現Write性狀的參數和使用創造BufWriter時,它工作正常。

我覺得前者應該可以做某事。

+0

爲什麼你認爲第一種方式應該是可能的?一個'BufWriterStruct '返回值意味着調用者可以選擇函數返回的內容,但這顯然不是你的方法中發生的事情。 – fjh

+0

那麼在我的實際案例中,我傳遞了另一個參數來告訴它要創建什麼類型。就像它會傳遞一個像流,文件等字符串一樣,新的會創建它。 我只是想新的做一切(創建文件/流,做任何需要的內容等)。 我可以只是移動新的文件/流的創建。 但我越想到它,我不認爲我想這樣做的方式是可能的。 –

回答

1

你的錯誤是在混合通用和具體:

impl <W: Write>BufWriterStruct<W> { 
    pub fn new(filename: &str) -> BufWriterStruct<W> { 
     BufWriterStruct { 
      writer: Some(BufWriter::new(File::create(filename).unwrap())), 
     } 
    } 
} 

在這裏,你的BufWriter實例應該接受W: Write,這是由主叫方決定,但功能實際上創建了一個File

讓來電者決定,而不是:

impl <W: Write> BufWriterStruct<W> { 
    pub fn new(writer: W) -> BufWriterStruct<W> { 
     BufWriterStruct { 
      writer: Some(BufWriter::new(writer)), 
     } 
    } 
} 

當然,這將改變調用了一下:

fn main() { 
    let tmp = BufWriterStruct::new(File::create("tmp.txt").unwrap()); 
} 

然後it'll work

1
impl <W: Write>BufWriterStruct<W> { 
    pub fn new(filename: &str) -> BufWriterStruct<W> 

這個簽名意味着下面的代碼是有效的:

let tmp : BufWriterStruct<Stdout> = BufWriterStruct::new("tmp.txt"); 

然而,這顯然不是你的實現new工作,因爲它會產生一個BufWriterStruct<File>,不<StdOut>。如果你想返回BufWriterStruct<File>,應該相應地宣告你的new功能:

pub fn new(filename: &str) -> BufWriterStruct<File> 

然而,單是這種變化將離開W參數上impl塊不受約束,編譯器將無法推斷出類型它。這樣做的最好的辦法是把new方法上的非通用impl

impl BufWriterStruct<File> { 
    pub fn new(filename: &str) -> BufWriterStruct<File> { 
     // ... 
    } 
} 

注意鏽不支持重載(名稱相同,但不同的參數列表的方法),所以如果你有兩個impl塊在同一類型上(不考慮通用參數),每個塊都使用一個名爲new的方法,在嘗試調用其中一個時出現錯誤(截至Rust 1.4.0,僅在單獨的impl中定義具有相同名稱的方法塊不是編譯時錯誤)。因此,您可能希望使用比new更明確的名稱。

+0

是的。我認爲他們的方式我想這樣做是不可能的。 我想我只是將它改變到我傳遞實現'Write'特性的參數的地方。然後我可以在'File','Stream'等上使用它。 –

相關問題