我正在尝试实例化一个参数解析器(clap)。 代码如下:
const DEFAULT_VALUE: &'static str = "12312312";
// ...
.help("this parameter is for (default:" + DEFAULT_VALUE + ")")
// ...
我查看了类似的现有问题并发现了concat! macro和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())
}
Cargo.toml
[package]
name = "demo-clap"
version = "1.0.0"
[dependencies]
clap = "2.10.0"
编译错误
<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`.
答案 0 :(得分:6)
您只需使用引用和format!
宏:
.help(&format!("this parameter is for (default: {})", DEFAULT_VALUE));
修改强>
What you want to do is not possible in Rust:
这是宏的一个基本限制,因为它们正在工作 只有各种代币。他们不了解 类型,只是看起来像类型的标记。当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())
}
使用宏而不是常量允许您使用concat!
宏。
答案 1 :(得分:1)
如果您使用的是Rust 1.46.0 1 或更高版本,请检查const_format
| crates.io上的docs.rs条板箱。 / p>
concatcp
:将integers
2 ,bool
和&str
常量连接到&'static str
中。
因此,在您的示例中,formatcp
将提供最灵活的解决方案,并且不需要您提及的局部变量(我假设您是指由alloc::fmt::format
生成的堆分配的String在format!
宏中):
use clap::{Arg, App};
use const_format::formatcp;
const DEFAULT: &'static str = "1";
fn main() {
let params = App::new("app")
.arg(Arg::with_name("p")
.help(formatcp!("parameter p (DEFAULT: {})", DEFAULT)))
.get_matches();
println!("param p = {}", params.value_of("p").unwrap())
}
运行app -h
会给出
app
USAGE:
app [p]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<p> parameter p (DEFAULT: 1)
包装箱中所有宏的限制:
&'static str
的宏(即我提到的宏)仅接受 concrete 类型的常量:
Type::<u8>::FOO
OK✅Type::<TYPE_PARAMETER>::FOO
不好i*/u*
后缀)。#[doc = "ab"]
!= #[doc = concatcp!("a", "b")]
1 stabilized const fn
improvements是必需的,它允许循环而无需涉及heinous hackery的“ std::mem::transmute”
2 更具体地说,这将是所有i*/u*
原语。请注意,如果您要传递文字,则必须constrain使用所需的后缀自己键入。