繁体   English   中英

在 clap 中动态生成带有格式化描述的子命令

[英]Dynamically generate subcommands with formatted description in clap

我想根据HashMap内容为clap生成子命令。 为此,我正在迭代这些项目以创建新的App实例。 问题是App.about()需要&str作为输入,而我无法从format!()宏中创建一个寿命足够长的输入。

这是一个示例( 操场):

use clap::App;
use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert("key", "value");
    map.insert("key2", "value2");
    map.insert("key3", "value3");

    let mut app = App::new("Test").version("1.0");

    for (key, value) in map.iter() {
        let about = format!("Value: {}", value);
        app = app.subcommand(App::new(*key)).about(about.as_str());
    }

    app.get_matches();
}

错误信息:

error[E0597]: `about` does not live long enough
  --> src/main.rs:14:52
   |
14 |         app = app.subcommand(App::new(*key)).about(about.as_str());
   |                                                    ^^^^^ borrowed value does not live long enough
15 |     }
   |     - `about` dropped here while still borrowed
16 | 
17 |     app.get_matches();
   |     --- borrow later used here

如何将格式化的字符串传递给about()方法?

首先,看起来您有一个不相关的错误,我会提到它只是为了减少对代码示例正确性的混淆。 我没有用clap自己,但它看起来像这样被改写应用程序的about反复

app = app.subcommand(App::new(*key)).about(about.as_str());

你可能是说

app = app.subcommand(App::new(*key).about(about.as_str()));

将其应用于子命令。


这里的问题是App不想拥有这些字符串,所以需要有另一个对象来拥有。 一种方法是构建一个包含format!的地图format! ted 字符串(因此拥有它们):

    let abouts: HashMap<String, String> = map.iter()
        .map(|(key, value)| (key.to_string(), format!("Value: {}", value)))
        .collect();
    for (key, about) in abouts.iter() {
        app = app.subcommand(App::new(key.as_str()).about(about.as_str()));
    }

地图abouts必须与app一样长。

如果你只打算在你的程序中这样做一次,那么你可能会泄漏内存format! 分配:

    for (key, value) in map.iter() {
        let about = &*Box::leak(format!("Value: {}", value).into_boxed_str());
        app = app.subcommand(App::new(*key).about(about));
    }

如果你希望能够回收内存,但不希望有处理类似构造的结构abouts之上,因为你实际的问题是比较复杂的,你可以使用typed_arena箱子提供一个地方分配任何数量的字符串并使它们保持活力:

use typed_arena::Arena;

...

    let arena = Arena::new();
    for (key, value) in map.iter() {
        let about = arena.alloc(format!("Value: {}", value)).as_str();
        app = app.subcommand(App::new(*key).about(about));
    }

就像在abouts解决方案中一样,只要您保留app ,您就需要保留arena

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM