如何将文字字符串与const字符串连接?

时间:2016-08-18 16:47:16

标签: rust

我正在尝试实例化一个参数解析器(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`.

2 个答案:

答案 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:类似format的格式(发出&'static str);与concatcp

    具有相同的原语

因此,在您的示例中,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不好
  • 整数参数必须为constrained(即使用文字时必须添加i*/u*后缀)。
  • 不能在仅使用字符串文字的某些地方使用,即attributes,它可能需要LiteralExpression
    • #[doc = "ab"]!= #[doc = concatcp!("a", "b")]

1 stabilized const fn improvements是必需的,它允许循环而无需涉及heinous hackery的“ std::mem::transmute
2 更具体地说,这将是所有i*/u*原语。请注意,如果您要传递文字,则必须constrain使用所需的后缀自己键入。