我在Rust中包装了一个C库,它的许多函数通过指向结构的指针来获取参数,这些结构本身通常具有指向其他结构的指针。为了减少开销,我希望能够将将Rust数据编组的结果缓存到C结构中。
以下是C库如何期望某些参数的示例:
#[repr(C)]
struct Foo {
x: i32,
y: f32
}
#[repr(C)]
struct Bar {
p_foo: *const Foo,
z: bool
}
我如何想象一个拥有,"缓存"版本看起来:
struct Cached {
foo: Option<Foo>,
bar: Bar
}
p_foo
的{{1}}字段将构建为指向bar
内的Some
值,如果存在foo
则指向空指针。
这个问题当然是,如果要移动None
的值,则直接Cached
将不合适,并且memcpy
还需要重定向。这在C ++中很容易确保,具有可定义的移动语义,但Rust除了提供bar.p_foo
之外还提供了一个解决方案,直到它被使用&#34;?虽然这样做肯定会有效,但我不能想象这些缓存的值会被移动超过(甚至接近它们被重用的频率),并且需要进行一些工作来设置这些指针,特别是如果嵌套/链接是深/长。我还不是bar.p_foo
堆上的子结构。
澄清一下,这里是我用C ++编写的内容,我想在Rust中复制:
Box
答案 0 :(得分:1)
Rust等效的是不使用原始指针,因为原始指针用于实现我们的安全数据结构,而不是用于实现普通数据结构。
#[repr(C)]
struct Foo {
x: i32,
y: f32
}
#[repr(C)]
struct Bar {
p_foo: Option<Box<Foo>>,
z: bool
}
Option<Box<T>>
保证与*const T
完全等效(在内存中的位数),只要T
是类型而不是特征。唯一的区别是在Rust中使用它是安全的。
这样您甚至不再需要Cached
结构,但可以直接传递Bar
对象。
我也不愿意在堆上装箱子结构。
然后我建议你不要留下Bar
物品,而是在需要将一个物品传递给C时召唤它:
#[repr(C)]
struct Foo {
x: i32,
y: f32
}
#[repr(C)]
struct Bar<'a> {
p_foo: Option<&'a Foo>,
z: bool
}
struct Cached {
foo: Option<Foo>,
z: bool,
}
impl Cached {
fn bar<'a>(&'a self) -> Bar<'a> {
Bar {
p_foo: self.foo.as_ref(),
z: self.z,
}
}
}
设置这些指针需要做一些工作,特别是如果嵌套/链接是深/长的话。
这听起来很像过早优化。不要优化您尚未进行基准测试的地方。