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

Sco*_*amb 2 lifetime rust

我正在尝试将一些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> { ... }
Run Code Online (Sandbox Code Playgroud)

并使用它们以尽可能少的堆分配附加大量和大量的切片.简化,像这样:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用.附加行会导致错误"f.slice_*活得不够长","引用必须对生命周期内的a有效'a在块上定义...","...但借用的值仅对于块后缀以下语句".我认为这与关于自引用结构的这个问题类似.这基本上是这样的,具有更多的间接性.而且显然这是不可能的.

那么我该怎么做呢?

我想我很乐意给予resource::Slicesin in append,但是我不能把resource::SliceSliceInfo用在in中,Vec<SliceInfo>因为它resource::Slice是一种特性,而且特征是不合格的.我可以Box<resource::Slice>改为做,但这意味着为每个切片分别进行堆分配.我想避免这种情况.(每个Mp4Resource可以有数千个切片.)

我正在考虑做一个枚举,比如:

enum BasicSlice {
    String(StringSlice),
    Lazy(LazySlice),
    File(FileSlice)
};
Run Code Online (Sandbox Code Playgroud)

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

还有其他选择吗?

oli*_*obk 5

你可以User为你的BasicSlice枚举添加一个变体,它需要一个Box<SliceInfo>.这样,只有用户的特殊情况才会进行额外分配,同时优化正常路径.