15 个版本 (稳定版)

2.1.4 2023 年 1 月 24 日
2.1.3 2023 年 1 月 23 日
1.1.5 2023 年 1 月 11 日
0.1.3 2022 年 12 月 14 日

Rust 模式 中排名第 471

每月下载 25

LGPL-3.0-or-later

15KB
150 代码行

dynarg

Build status crates.io Documentation

一个简单的动态参数系统

你是否曾想拥有多个具有相同签名但具有非常不同用途和行为的功能?

  • 也许你想制作一个图像编辑应用程序,拥有许多工具。
  • 也许你想制作一个 Rust GCODE 实现。
  • 也许你只是想制作一个模块化外壳程序,像摘草莓一样动态地选择参数,同时跟踪哪些参数尚未使用。

无论如何,你可能需要一个可以

  • 将参数与静态字符串匹配,以避免运行时开销,同时保持可读性。
  • 可能处理动态字符串(如果需要)。
  • 处理任意参数类型。
  • 提供用于处理参数的便利函数 -- 例如,常见类型的包装函数。

如果你有以上任何一种需求,这是一个值得考虑的库。请注意,对于 非常 高性能的应用程序,可能最好使用自定义用例(例如,使用枚举的 Vec,最好是回收的!)来避免动态调度。

这个 API 目前被认为是稳定的,并且相对成熟。它是 forbid_unsafe,并且是用纯 Rust 编写的。

基本示例

use dynarg::Args;

fn main() {
    // Creating Args object
    let mut args = Args::new();
    // Inserting a string type
    args.insert_string("greeting", String::from("hello world"));
    // Inserting an i32 type
    args.insert_i32("meaning_of_life", 42);
    // There's a lot more types where that came from, BTW :)
    // (In fact, you can use any type that implements `Any`,
    // which... I think should be any?)
    
    // Retrieving string type
    let out = args.get_string("greeting").unwrap();
    println!("{}", out);
    // Retrieving i32
    let meaning_of_life = args.get_i32("meaning_of_life").unwrap();
    println!("The meaning of life is: {}", meaning_of_life);
}

跟踪哪个参数被使用

use dynarg::Args;

fn main() {
    // Creating Args object
    let mut args = Args::new();
    // Inserting a string type
    args.insert_string("greeting", String::from("hello world"));
    // Inserting an i32 type
    args.insert_i32("meaning_of_life", 42);
    // There's a lot more types where that came from, BTW :)
    // (In fact, you can use any type that implements `Any`, which... I think should be any?)
        
    // Retrieving string type (while marking used flag!)
    let out = args.poke_string("greeting").unwrap();
    println!("{}", out);
    // Retrieving i32 (also while marking used flag!)
    let meaning_of_life = args.poke_i32("meaning_of_life").unwrap();
    println!("The meaning of life is: {}", meaning_of_life);
    // NOTE: the difference between poke and poke_* functions, and get and get_,
    // is that poke marks the status as used.
    // Note that this only exists if `used` feature is enabled for library.
    // Explicitly marking status is used is useful for sanity checking -- e.g.
    
    // Checking used status of args is useful for catching
    // what would otherwise be silent or hard-to-catch errors
    if args.all_used() {
        println!("All used! :3");
    } else {
        for used_arg_name in args.iter_not_used_name() {
            println!("Arg: \"{}\" not used", used_arg_name);
        }
    }
}

更复杂的示例

use dynarg::*;

/// Where normally you'd need to have a fixed set of arguments,
/// each of which would be roughly fixed types
/// -- you can dynamically push arguments on the fly instead.
/// This is useful when you need a consistent function signature
/// for different types of functions,
/// each needing different arguments
fn draw(args: &mut Args) {
    if let Ok(greeting) = args.poke_string("greeting") {
        println!("{} world", greeting);
    }
    if let Ok(arg) = args.poke::<Fruit>("fruit_to_draw") {
        println!("I will draw {}!", arg.0);
        if let Ok(size) = args.poke::<f32>("size") {
            println!("with a size of {}", size);
        }
    } else {
        panic!("Nothing to draw D:");
    }
}

/// A custom struct as an example
struct Fruit<'a>(&'a str);

fn main() {
   let mut args = Args::default();

    let apple = Fruit("apple");
    // This is how you add arguments
    args.insert("fruit_to_draw", Box::new(apple));
    args.insert("size", Box::new(5.2f32));
    let greeting = String::from("henlo");
    args.insert_string("greeting", greeting);
    draw(&mut args);
    if !args.all_used() {
        println!("Warning! I didn't use all my arguments D:");
    }
    // Clear all the used flags on args
    args.reset_used_status();
}

GitHub 仓库在这里。

欢迎 Pull Requests :)

待办事项

  • 自定义类型处理
  • Option 替换为 Result,以便可以确定是否不存在参数名称,或者类型不正确
  • 添加 snafu
  • 添加便利函数(例如,get_string()get_int()
  • 正确记录注意事项
  • 添加不带used()功能的变体。
  • 添加更多示例
  • 基准测试

依赖关系

~2.2–4MB
~68K SLoC