2016-05-17 29 views
1

我試圖將一些C++代碼移植到Rust。它從幾種切片(字符串引用,延遲評估的字符串引用,物理文件的一部分)組成一個虛擬(.mp4)文件,並根據結果提供HTTP請求。 (如果您好奇,請參閱Mp4File,它利用FileSlice接口及其在http.h中的具體實現。)Vec <MyTrait>沒有N堆分配?

以下是問題所在:我希望儘可能少地需要堆分配。假設我有一些resource::Slice的實現,我希望可以自己弄清楚。然後我想使該組成他們所有的一個:

pub trait Slice : Send + Sync { 
    /// Returns the length of the slice in bytes. 
    fn len(&self) -> u64; 

    /// Writes bytes indicated by `range` to `out.` 
    fn write_to(&self, range: &ByteRange, 
       out: &mut io::Write) -> io::Result<()>; 
} 

// (used below) 
struct SliceInfo<'a> { 
    range: ByteRange, 
    slice: &'a Slice, 
} 

/// A `Slice` composed of other `Slice`s.  
pub struct Slices<'a> { 
    len: u64, 
    slices: Vec<SliceInfo<'a>>, 
} 

impl<'a> Slices<'a> { 
    pub fn new() -> Slices<'a> { ... } 
    pub fn append(&mut self, slice: &'a resource::Slice) { ... } 
} 

impl<'a> Slice for Slices<'a> { ... } 

,並用它們來追加很多很多片用盡可能少的堆分配成爲可能。簡化,像這樣:

struct ThingUsedWithinMp4Resource { 
    slice_a: resource::LazySlice, 
    slice_b: resource::LazySlice, 
    slice_c: resource::LazySlice, 
    slice_d: resource::FileSlice, 
} 

struct Mp4Resource { 
    slice_a: resource::StringSlice, 
    slice_b: resource::LazySlice, 
    slice_c: resource::StringSlice, 
    slice_d: resource::LazySlice, 
    things: Vec<ThingUsedWithinMp4Resource>, 
    slices: resource::Slices 
} 

impl Mp4Resource { 
    fn new() { 
     let mut f = Mp4Resource{slice_a: ..., 
           slice_b: ..., 
           slice_c: ..., 
           slices: resource::Slices::new()}; 
     // ...fill `things` with hundreds of things... 
     slices.append(&f.slice_a); 
     for thing in f.things { slices.append(&thing.slice_a); } 
     slices.append(&f.slice_b); 
     for thing in f.things { slices.append(&thing.slice_b); } 
     slices.append(&f.slice_c); 
     for thing in f.things { slices.append(&thing.slice_c); } 
     slices.append(&f.slice_d); 
     for thing in f.things { slices.append(&thing.slice_d); } 
     f; 
    } 
} 

但這不起作用。附加行會導致錯誤「f.slice_ *活得不夠長」,「引用必須對在塊中定義的生命週期a有效」,「...」,但借用的值僅對塊後綴下面的語句「。我認爲這與關於自引用結構的this question類似。這基本上是這樣,更多的間接。顯然這是不可能的。

那我能做些什麼呢?

我想我會很樂意給所有權的resource::Slicesappend,但我不能把在Vec<SliceInfo>使用的SliceInfo一個resource::Slice因爲resource::Slice是一個特點和特徵,是未分級。我可以改爲Box<resource::Slice>,但這意味着每個片的單獨堆分配。我想避免這種情況。 (可以有上千個Mp4Resource切片。)

我想在做一個枚舉,喜歡的東西的:

enum BasicSlice { 
    String(StringSlice), 
    Lazy(LazySlice), 
    File(FileSlice) 
}; 

和使用,在SliceInfo。我想我可以做這個工作。但它絕對限制了我的resource::Slices課程的效用。我希望允許它在我沒有預料到的情況下使用,最好不必每次都定義一個新的枚舉。

還有其他的選擇嗎?

+2

如果結構中包含有限的生命週期項,則該結構的生命週期也有限。 – WiSaGaN

+0

@WiSaGaN在結構體中包含一個有限生命週期的項目是什麼意思?我的第一個方法是包含一個只有結構體纔會存在的項目。但我認爲沒有辦法來表達這一生,因此自引用結構是不可能的。無論如何,我很高興找到另一種方式,正如我在問題中所說的那樣...... –

+0

嗯,除非這不完全正確。至少在C++中,一個類的成員是按照相反的順序被構造的,然後我有一個後來的成員引用了一個早期的成員。這是一件安全的事情,如果有幫助,我會很樂意在兩個單獨的堆分配中完成它們。但似乎仍然需要通過一生... –

回答

4

您可以將User變體添加到BasicSlice枚舉中,其格式爲Box<SliceInfo>。這樣,只有用戶的特殊情況纔會進行額外的分配,而正常路徑則進行了優化。