我正在寻找在编译时静态注册结构的正确方法。
这个要求的起源是有一堆小程序有专门的任务,这样如果我运行myprog foo
,它会调用foo
小程序。
所以我开始定义一个 Applet
结构:
struct Applet {
name: &str,
call: fn(),
}
然后我可以这样定义我的 foo
applet:
fn foo_call() {
println!("Foo");
}
let foo_applet = Applet { name: "foo", call: foo_call };
现在我想注册这个小程序,这样我的 main
函数就可以调用它了:
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
match AppletRegistry.get(args[1]) {
Some(x) => x.call(),
_ => (),
}
}
整个交易是关于如何实现 AppletRegistry
以便我可以最好在编译时列出所有可用的 applet。
最佳答案
你不能。
Rust 的一个有意识的设计选择是“main
之前没有代码”,因此不支持这种事情。从根本上说,您需要在某处明确调用注册小程序的代码。
需要执行此类操作的 Rust 程序将明确列出所有可能的实现,并构造一个单一的静态数组。像这样:
pub const APPLETS: &'static [Applet] = [
Applet { name: "foo", call: ::applets::foo::foo_call },
Applet { name: "bar", call: ::applets::bar::bar_call },
];
(有时,重复的元素可以用宏来简化,即在这个例子中,你可以改变它,让名字只被提及一次。)
理论上,您可以通过像 D 这样的语言在幕后执行的操作来实现它,但这将是特定于平台的,并且可能需要弄乱链接器脚本和/或修改编译器。
旁白:#[test]
呢? #[test]
很神奇,由编译器处理。简短的版本是:它的工作是在箱子中找到所有测试并构建所述巨型列表,然后测试运行器使用它有效地替换你的 main
功能。不,您无法做任何类似的事情。
关于rust - 如何在编译时静态注册结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32678845/