我试图实例化一个参数解析器(clap).有代码如:
const DEFAULT_VALUE: &'static str = "12312312";
// ...
.help("this parameter is for (default:" + DEFAULT_VALUE + ")")
// ...
Run Code Online (Sandbox Code Playgroud)
我查看了类似的现有问题并发现了concat!宏和lazy_static.
第一个选项不合适,lazy_static没有示例.如果可能的话,它将会过于复杂,因为lazy_static需要在一个单独的地方定义一个块.
我正在寻找一些简洁的语法糖与一个宏,没有很多类型的开销.
如果定义一个局部变量,它可能会变高,因为拍拍的DSL可能会很长.它不方便,因为它从代码中的逻辑位置撕掉了字符串.
另一种为整个帮助字符串定义静态变量的方法,但它具有与上述方法相同的缺点以及命名空间污染.
建议的格式解决方案!也不适合.它需要定义一个局部变量.
例
extern crate clap;
use clap::{Arg, App};
const DEFAULT: &'static str = "1";
fn main() {
let params = App::new("app")
.arg(Arg::with_name("p")
// here 100 lines of the uninterruptable expression
.help(&format!("parameter p (DEFAULT: {})", DEFAULT)))
// here also 100 lines of the uninterruptable expression
.get_matches();
println!("param p = {}", params.value_of("p").unwrap())
}
Run Code Online (Sandbox Code Playgroud)
Cargo.toml
[package]
name = "demo-clap"
version = "1.0.0"
[dependencies]
clap = "2.10.0"
Run Code Online (Sandbox Code Playgroud)
编译错误
<std macros>:2:1: 2:61 error: borrowed value does not live long enough
<std macros>:2 $ crate :: fmt :: format ( format_args ! ( $ ( $ arg ) * ) ) )
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:11:21: 11:66 note: in this expansion of format! (defined in <std macros>)
src/main.rs:13:24: 15:2 note: reference must be valid for the block suffix following statement 0 at 13:23...
src/main.rs:13 .get_matches();
^
src/main.rs:8:5: 13:24 note: ...but borrowed value is only valid for the statement at 8:4
src/main.rs:8 let params = App::new("app")
^
src/main.rs:8:5: 13:24 help: consider using a `let` binding to increase its lifetime
src/main.rs:8 let params = App::new("app")
^
error: aborting due to previous error
error: Could not compile `demo-clap`.
Run Code Online (Sandbox Code Playgroud)
Yen*_*ang 17
如果您使用Rust 1.46.0 1或更高版本,请查看const_format( crates.io | docs.rs ) 上的包。
concatcp:将integers2、、bool和&str常数连接成&\'static str。
因此,对于您的示例,formatcp将提供最灵活的解决方案,并且不需要您提到的局部变量(我假设您指的是宏alloc::fmt::format中产生的堆分配的字符串format!):
use clap::{Arg, App}; \nuse const_format::formatcp; \n \nconst DEFAULT: &\'static str = "1"; \n\nfn main() { \n let params = App::new("app") \n .arg(Arg::with_name("p") \n .help(formatcp!("parameter p (DEFAULT: {})", DEFAULT))) \n .get_matches(); \n println!("param p = {}", params.value_of("p").unwrap()) \n}\nRun Code Online (Sandbox Code Playgroud)\n跑步app -h 给予
app \n\nUSAGE:\n app [p]\n\nFLAGS:\n -h, --help Prints help information\n -V, --version Prints version information\n\nARGS:\n <p> parameter p (DEFAULT: 1)\nRun Code Online (Sandbox Code Playgroud)\n板条箱中所有宏的限制:
\n&\'static str(即我提到的那些)的宏仅接受具体类型的常量:\nType::<u8>::FOO 确定 \xe2\x9c\x85Type::<TYPE_PARAMETER>::FOO坏 \xe2\x9d\x8ci*/u*后缀)。#[doc = "ab"]!= #[doc = concatcp!("a", "b")]1这是稳定const fn改进所必需的,它允许循环而无需涉及std::mem::transmute的“令人发指的黑客行为
” \n 2更具体地说,这将是所有i*/u* 原语。请注意,如果您传递文字,则必须使用所需的后缀自行约束类型。
您只需使用引用和format!宏:
.help(&format!("this parameter is for (default: {})", DEFAULT_VALUE));
Run Code Online (Sandbox Code Playgroud)
编辑:
这是宏的一个基本限制,因为它们只使用各种令牌.他们不了解类型,只是看起来像类型的标记.当concat!看到描述它只看到一个标识符,它不知道它是一个字符串常量.这里可以使用的是某种字符串连接const fn,因为它可以采用常量的值来创建新的常量,尽管这需要一些黑魔法.
你可以这样做:
macro_rules! DEFAULT {
() => { "1" };
}
fn main() {
let params = App::new("app")
.arg(Arg::with_name("p")
// here 100 lines of the uninterruptable expression
.help(concat!("parameter p (DEFAULT: ", DEFAULT!(), ")")))
// here also 100 lines of the uninterruptable expression
.get_matches();
println!("param p = {}", params.value_of("p").unwrap())
}
Run Code Online (Sandbox Code Playgroud)
使用宏而不是常量允许您使用concat!宏.