Closure

2 文章

FFI 回调和 void *ctx

4 分钟

C 里的回调接口通常长这样:

typedef void (*event_cb_t)(void *ctx, int event);

int device_register_callback(struct device *dev, event_cb_t cb, void *ctx);
void device_unregister_callback(struct device *dev);

这个设计很常见:函数指针负责执行,ctx 负责保存调用方环境。

Rust 内部可以用 closure 表达“代码 + 环境”。但跨 C ABI 时,捕获环境的 closure 不能直接变成 C 函数指针。C 只认识固定 ABI 的函数地址和一个 void *ctx。

阅读更多

closure 和回调

4 分钟

C 里写回调,最常见的形状是函数指针加上下文指针:

typedef void (*event_cb_t)(void *ctx, int event);

void register_event(event_cb_t cb, void *ctx);

cb 是要调用的函数,ctx 是调用时带回来的环境。这个模式很成熟,但也有老问题:

  • ctx 的真实类型靠约定
  • ctx 活多久靠约定
  • 回调会不会修改环境靠约定
  • 回调会不会只调用一次靠约定
  • 多线程调用时是否安全靠约定

Rust 的 closure 解决的是同一个问题:把“要执行的代码”和“它需要的环境”放在一起。

阅读更多