【发布时间】:2016-05-17 04:34:39
【问题描述】:
我正在尝试将一些 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;
}
}
但这不起作用。附加行会导致错误“f.slice_* 寿命不够长”、“引用必须在...的块上定义的生命周期 'a 内有效”、“...但是借用的值仅对语句块后缀"。我认为这类似于this question 关于自引用结构。基本上就是这样,有更多的间接性。显然这是不可能的。
那我能做些什么呢?
我想我很乐意将所有权授予append 中的resource::Slices,但我不能在Vec<SliceInfo> 中使用的SliceInfo 中添加resource::Slice,因为resource::Slice 是一个特征,并且特征没有大小。我可以改为使用Box<resource::Slice>,但这意味着为每个切片分配单独的堆。我想避免这种情况。 (每个 Mp4Resource 可以有数千个切片。)
我正在考虑做一个枚举,比如:
enum BasicSlice {
String(StringSlice),
Lazy(LazySlice),
File(FileSlice)
};
并在SliceInfo 中使用它。我想我可以完成这项工作。但它肯定会限制我的resource::Slices 类的效用。我想让它在我没有预料到的情况下轻松使用,最好不必每次都定义一个新的枚举。
还有其他选择吗?
【问题讨论】:
-
如果结构体中包含有限生命周期项,则该结构体也具有有限生命周期。
-
@WiSaGaN 关于在结构中包含有限生命周期的项目有什么说法?我的第一种方法是包含一个与结构一样长的项目。但我认为没有办法表达那个生命周期,因此自引用结构是不可能的。无论如何,正如我在问题中所说的那样,我很高兴找到另一种方式......
-
好吧,但事实并非如此。至少在 C++ 术语中,一个类的成员是按顺序构造的,然后以相反的顺序被破坏,我有一个后来的成员,它引用了一个早期的成员。这是一件安全的事情,如果有帮助的话,我很乐意在两个单独的堆分配中完成它们。但似乎不管怎样,这辈子还是要过去的……