我正在用 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
}
bar
的 p_foo
字段将被构造为指向 foo
中的 Some
值,或者一个 null如果有 None
的指针。
当然,这里的问题是,如果要 move Cached
的值,直接的 memcpy
是不合适的,bar.p_foo
还需要重定向。这在 C++ 中很容易确保,因为它具有可定义的 move 语义,但是 Rust 是否提供了除了“在使用之前不要设置 bar.p_foo
”之外的解决方案?虽然这样做肯定会奏效,但我不认为这些缓存值的 move 频率会超过(甚至接近)它们被重用的频率,而且设置这些缓存值需要做一些工作指针,特别是如果嵌套/链接很深/很长。我也不希望 Box
堆上的子结构。
澄清一下,这是我可以用 C++ 编写的,我想在 Rust 中复制:
struct Foo {
int x;
float y;
};
struct Bar {
Foo const*pFoo;
bool z;
};
// bear with me while I conjure up a Maybe for C++
class Cached {
public:
// would have appropriate copy constructor/assignment
Cached(Cached &&other) {
m_foo = other.m_foo;
m_bar = other.m_bar;
if(m_foo.isJust()) {
m_bar.pFoo = &m_foo.value();
} // else already nullptr
}
// similar move assignment
private:
Maybe<Foo> m_foo;
Bar m_bar;
};
最佳答案
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
对象。
I'd also rather not Box the substructures up on the heap.
那我建议你不要保留Bar
object around,而是在需要将一个传递给 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,
}
}
}
there is a bit of work involved to set up these pointers, especially if the nesting/chaining is deep/long.
这听起来很像过早的优化。不要在没有进行基准测试的地方进行优化。
关于rust - Rust 中的 move 语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36188870/