我试图将一些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
中添加SliceInfo
在Vec<SliceInfo>
中使用,因为resource::Slice
是一个特征,而且特征是未分级的。我可以改为Box<resource::Slice>
,但这意味着每个切片都有一个单独的堆分配。我想避免这种情况。 (每个Mp4Resource可以有数千个切片。)
我想做一个枚举,比如:
enum BasicSlice {
String(StringSlice),
Lazy(LazySlice),
File(FileSlice)
};
并在SliceInfo
中使用它。我想我可以做到这一点。但它绝对限制了我的resource::Slices
类的效用。我希望允许它在我没有预料到的情况下轻松使用,最好不必每次都定义新的枚举。
还有其他选择吗?
答案 0 :(得分:5)
您可以在User
枚举中添加BasicSlice
变体,其中Box<SliceInfo>
为no-cache
。这样,只有用户的特殊情况才会进行额外分配,同时优化正常路径。