更新时间:2023-11-25 11:09:46
我不知道除了措辞强硬的文档之外,没有办法强制在主线程中调用方法.因此,忽略该要求... :-)
I know of no way of enforcing that a method be called in the main thread beyond strongly-worded documentation. So, ignoring that requirement... :-)
通常,我会使用 std::sync::Once
,这似乎基本上是为这种情况设计的:
Generally, I'd use std::sync::Once
, which seems basically designed for this case:
一种同步原语,可用于运行一次性全局初始化.用于 FFI 或相关的一次性初始化功能.这种类型只能用 ONCE_INIT
构造价值.
A synchronization primitive which can be used to run a one-time global initialization. Useful for one-time initialization for FFI or related functionality. This type can only be constructed with the
ONCE_INIT
value.
请注意,没有任何清理的规定;很多时候你只需要泄漏图书馆所做的一切.通常,如果一个库有一个专用的清理路径,它也被构造为将所有初始化数据存储在一个类型中,然后作为某种上下文或环境传递到后续函数中.这将很好地映射到 Rust 类型.
Note that there's no provision for any cleanup; many times you just have to leak whatever the library has done. Usually if a library has a dedicated cleanup path, it has also been structured to store all that initialized data in a type that is then passed into subsequent functions as some kind of context or environment. This would map nicely to Rust types.
警告
您当前的代码没有像您希望的那样具有保护性.由于您的 App
是一个空结构,最终用户可以在不调用您的方法的情况下构建它:
Your current code is not as protective as you hope it is. Since your App
is an empty struct, an end-user can construct it without calling your method:
let _init_ = App;
我们将使用零大小的参数来防止这种情况.另请参阅定义指向 C 不透明指针的字段的 Rust 习语是什么? 了解为以下对象构造不透明类型的正确方法外国金融机构.
We will use a zero-sized argument to prevent this. See also What's the Rust idiom to define a field pointing to a C opaque pointer? for the proper way to construct opaque types for FFI.
总而言之,我会使用这样的东西:
Altogether, I'd use something like this:
use std::sync::Once;
mod ffi {
extern "C" {
pub fn InitializeMyCLib();
pub fn CoolMethod(arg: u8);
}
}
static C_LIB_INITIALIZED: Once = Once::new();
#[derive(Copy, Clone)]
struct TheLibrary(());
impl TheLibrary {
fn new() -> Self {
C_LIB_INITIALIZED.call_once(|| unsafe {
ffi::InitializeMyCLib();
});
TheLibrary(())
}
fn cool_method(&self, arg: u8) {
unsafe { ffi::CoolMethod(arg) }
}
}
fn main() {
let lib = TheLibrary::new();
lib.cool_method(42);
}