【问题标题】:Pass a Rust trait to C将 Rust 特征传递给 C
【发布时间】:2015-06-07 17:22:08
【问题描述】:

我正在构建一个 Rust 库,它需要使用 Rust 对象调用一些 C 函数。我有一个调用 C 函数的函数的 trait,C 函数在 Rust 中定义如下:

extern {
    fn process_trait(my_trait: MyTrait);
}

这个想法是用户可以为他的结构实现 trait,然后调用 C 函数(基本上,C 然后调用其他一些 Rust,后者调用一些 Trait 函数)。这里的错误是:the trait core::marker::Sized is not implemented for the type Self,因为我将*self 传递给process_trait。难道我做错了什么?我试着改变了一点,即使是铸造,我得到这个错误或错误的类型。

我认为问题在于它应该是堆分配的,不是吗?我唯一要避免的是 API 看起来很丑。用户应该能够

struct MyUnit;
impl MyTrait for MyUnit...
MyUnit.callC();

【问题讨论】:

    标签: c rust ffi


    【解决方案1】:

    通过值传递 trait 对象没有意义,尤其是在与 C 交互时。实际类型(在 C 意义上)及其大小是未知的,并且对象内部没有 vtable。您很可能希望传递特征参考 (&MyTrait)。 然而,特征对 C 来说是陌生的,因此会产生一个糟糕的接口。虽然您可以在 C 中定义 core::raw::TraitObject 的等价物,但实际上对 vtable 做任何事情都是极其丑陋、脆弱和不安全的。

    如果您需要跨越 Rust-C 屏障的多态性,显式函数指针是一个非常更好的选择。您仍然可以使用 MyTraitcallC 方法,只是 FFI 部分看起来不同。可以将对象作为有效负载处理 C 库回调。

    或者,传递前面提到的TraitObjects(胖指针)但从不从 C 中检查它们,通过 Rust 中的(非特征)辅助函数调用方法:

    extern fn call_method(obj: TraitObject) {
        let obj: &MyTrait = transmute(obj); // should be safe, but not tested
        obj.meth();
    }
    

    这避免了在 C 中手动挖掘 Rust vtable 的麻烦。

    【讨论】:

    • 我不是什么大专家,所以我可能不太了解您在这里写的内容,但我确实对结尾有意见。除了在 Rust 代码(具有回调)之间创建桥梁外,C 不会以任何方式与数据交互。我将测试这种方法,但它似乎是正确的东西(从解释来看)。谢谢
    • 但是如何将这个TraitObject 代码集成到我的特征函数中?
    • @User 该代码不属于任何特征。这是一个独立函数,它允许 C 代码调用 &MyTrait 上的方法,而无需知道 Rust 如何实现对 trait 对象的方法调用。
    • 我想你误会了,C 代码不需要与 trait 交互,只需将 trait 传递给 rust 回调
    • @User 请在问题中添加更具体的描述,说明您正在尝试做什么(以及使用哪种语言)。伪代码示例等。我很难准确地想象你遇到了什么问题。
    猜你喜欢
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2020-05-09
    • 1970-01-01
    相关资源
    最近更新 更多