没有N堆分配的Vec <mytrait>?

时间:2016-05-17 04:34:39

标签: rust lifetime

我试图将一些C ++代码移植到Rust。它由几种切片(字符串引用,延迟评估的字符串引用,物理文件的一部分)组成虚拟(.mp4)文件,并根据结果提供HTTP请求。 (如果您有点好奇,请参阅Mp4File,它利用了FileSlice接口及其在http.h中的具体实现。)

问题在于:我想要尽可能少的堆分配。让我们说我有一些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;
    }
}

但这不起作用。附加行导致错误&#34; f.slice_ *活不够长&#34;,&#34;引用必须在生命周期内有效&#39; a在块上定义...&#34 ;,&#34; ...但借用的值仅对语句&#34;后面的块后缀有效。我认为这与自我引用结构的this question类似。这基本上是这样的,具有更多的间接性。显然这是不可能的。

那么我该怎么做呢?

我认为我很乐意为resource::Slices中的append提供所有权,但我无法在resource::Slice中添加SliceInfoVec<SliceInfo>中使用,因为resource::Slice是一个特征,而且特征是未分级的。我可以改为Box<resource::Slice>,但这意味着每个切片都有一个单独的堆分配。我想避免这种情况。 (每个Mp4Resource可以有数千个切片。)

我想做一个枚举,比如:

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

并在SliceInfo中使用它。我想我可以做到这一点。但它绝对限制了我的resource::Slices类的效用。我希望允许它在我没有预料到的情况下轻松使用,最好不必每次都定义新的枚举。

还有其他选择吗?

1 个答案:

答案 0 :(得分:5)

您可以在User枚举中添加BasicSlice变体,其中Box<SliceInfo>no-cache。这样,只有用户的特殊情况才会进行额外分配,同时优化正常路径。