譬如,在 nginx 的C源码里,下面的 void *ctx 代码非常常见。 因为 context的类型可能千奇百怪,无法预测,只能用一个 void *来表示。 linux kernel 里也是大量的类似代码。 请问: rust里该如何正确的做呢?
struct ngx_module_s {
ngx_uint_t ctx_index;
ngx_uint_t index;
char *name;
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t version;
const char *signature;
void *ctx;
ngx_command_t *commands;
ngx_uint_t type;
}
1
共 13 条评论, 1 页
评论区
写评论C使用
void*
是因为C的表达能力被限制了,没有更好的方法……C++通过带虚函数的class(本质上就是约定了一个事先指定方法的void*,也就是this指针)来做到C中void*的事情。Rust中就是trait。当然你要ffi的话那还是只能用c_void。如果不是明确的类型,rust比较难。 void *就是c/c++的不安全根本来源。
插件是不是定义个trait就可以了,不需要感知插件内部的数据类型。如果是为了用ctx传参的话,可以试试换成scope传参(参考这里:https://github.com/reiase/hyperparameter/tree/master/core/examples):
--
👇
sankred9527:
https://doc.rust-lang.org/stable/std/task/struct.RawWaker.html
譬如这个模块。又或者你自己做个支持plugin的系统,你没法预料plugin的作者用的数据类型,怎么用enum 呢?
--
👇
jiacai2050: IMO,
void *
算是 C 里面的“糟粕”了,Rust 里完全有更好的做法,如果你想表示的类型比较多,而且可以用一个 enum 来表示,而不是想 C 里面对void *
强转。楼主可以想一下 interface 这个概念,这层抽象就是为了不用考虑具体类型,只要这些类型有共有的行为即可,极端一点这个共有的行为可以是输出一个代表类型的编码,那这层抽象就可以囊括所有类型了,具体实现上楼主可以搜一搜 vtable 这个概念,我记得是从 C++ 的虚函数表的实现中传过来的。
我自己会把用 void * 看作在 C 中做类型抹除,和指针类型转换一起为 C 赋予了动态类型语言的灵活性。在 Rust 中我记得通常用 &dyn Trait(极端一点就是 &dyn Any) 来做类型抹除。
手动使用RawWaker构建Waker的函数是unsafe,RawWakerVTable里的函数也全是unsafe,安不安全取决于你写的代码如何编写的。https://doc.rust-lang.org/stable/src/alloc/task.rs.html#108 这么写就是安全的。
--
👇
sankred9527: 我看了 RawWaker的代码了, 本质上和 void *差不多
请看 RawWaker 的这部分代码: https://doc.rust-lang.org/stable/src/core/task/wake.rs.html#99
请问, 如果按照RawWaker这样做,那本质上和C的 void * 一样不安全了?
--
👇
Bai-Jinlin: https://doc.rust-lang.org/stable/std/task/struct.RawWaker.html
你这样可以,但是体现不出来 rust 相对于 C 的 “优越性” , 没法装逼啊, 哈哈
--
👇
ManonLoki: use std::ffi::c_void;
#[repr(C)] sturct Context{ data:i32 }
extern "C" fn function_name(context: mut c_void) { // 在这里处理 ptr 转换为对应类型 let context: &Context = unsafe { &(context as *const Context) }; } 好像是这样
https://doc.rust-lang.org/stable/std/task/struct.RawWaker.html
譬如这个模块。又或者你自己做个支持plugin的系统,你没法预料plugin的作者用的数据类型,怎么用enum 呢?
--
👇
jiacai2050: IMO,
void *
算是 C 里面的“糟粕”了,Rust 里完全有更好的做法,如果你想表示的类型比较多,而且可以用一个 enum 来表示,而不是想 C 里面对void *
强转。我看了 RawWaker的代码了, 本质上和 void *差不多
请看 RawWaker 的这部分代码: https://doc.rust-lang.org/stable/src/core/task/wake.rs.html#99
请问, 如果按照RawWaker这样做,那本质上和C的 void * 一样不安全了?
--
👇
Bai-Jinlin: https://doc.rust-lang.org/stable/std/task/struct.RawWaker.html
use std::ffi::c_void;
#[repr(C)] sturct Context{ data:i32 }
extern "C" fn function_name(context: mut c_void) { // 在这里处理 ptr 转换为对应类型 let context: &Context = unsafe { &(context as *const Context) }; } 好像是这样
*const ()
IMO,
void *
算是 C 里面的“糟粕”了,Rust 里完全有更好的做法,如果你想表示的类型比较多,而且可以用一个 enum 来表示,而不是想 C 里面对void *
强转。https://doc.rust-lang.org/stable/std/task/struct.RawWaker.html